diff options
469 files changed, 9059 insertions, 5921 deletions
diff --git a/apct-tests/perftests/contentcapture/Android.bp b/apct-tests/perftests/contentcapture/Android.bp index 66d7348008ab..19a66ad9f27b 100644 --- a/apct-tests/perftests/contentcapture/Android.bp +++ b/apct-tests/perftests/contentcapture/Android.bp @@ -20,9 +20,10 @@ android_test { "androidx.test.rules", "androidx.annotation_annotation", "apct-perftests-utils", - "collector-device-lib-platform", + "collector-device-lib", "compatibility-device-util-axt", ], platform_apis: true, test_suites: ["device-tests"], + data: [":perfetto_artifacts"], } diff --git a/apct-tests/perftests/contentcapture/AndroidManifest.xml b/apct-tests/perftests/contentcapture/AndroidManifest.xml index ee5577f265fa..80957c78abf3 100644 --- a/apct-tests/perftests/contentcapture/AndroidManifest.xml +++ b/apct-tests/perftests/contentcapture/AndroidManifest.xml @@ -16,11 +16,6 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.perftests.contentcapture"> - <uses-sdk android:targetSdkVersion="28" /> - - <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> - <uses-permission android:name="android.permission.REAL_GET_TASKS" /> - <application> <uses-library android:name="android.test.runner" /> <activity android:name="android.view.contentcapture.CustomTestActivity" diff --git a/apct-tests/perftests/contentcapture/AndroidTest.xml b/apct-tests/perftests/contentcapture/AndroidTest.xml index d2386bb1efea..d8e0a17d3935 100644 --- a/apct-tests/perftests/contentcapture/AndroidTest.xml +++ b/apct-tests/perftests/contentcapture/AndroidTest.xml @@ -21,7 +21,39 @@ <option name="test-file-name" value="ContentCapturePerfTests.apk" /> </target_preparer> + <!-- Needed for pushing the trace config file --> + <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/> + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> + <option name="push-file" key="trace_config_detailed.textproto" value="/data/misc/perfetto-traces/trace_config.textproto" /> + </target_preparer> + + <!-- Needed for pulling the collected trace config on to the host --> + <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector"> + <option name="pull-pattern-keys" value="perfetto_file_path" /> + </metrics_collector> + + <!-- Needed for storing the perfetto trace files in the sdcard/test_results--> + <option name="isolated-storage" value="false" /> + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > <option name="package" value="com.android.perftests.contentcapture" /> + + <!-- Listener related args for collecting the traces and waiting for the device to stabilize. --> + <option name="device-listeners" value="android.device.collectors.ProcLoadListener,android.device.collectors.PerfettoListener" /> + <!-- Guarantee that user defined RunListeners will be running before any of the default listeners defined in this runner. --> + <option name="instrumentation-arg" key="newRunListenerMode" value="true" /> + + <!-- ProcLoadListener related arguments --> + <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before starting the test run --> + <option name="instrumentation-arg" key="procload-collector:per_run" value="true" /> + <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3" /> + <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000" /> + <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000" /> + + <!-- PerfettoListener related arguments --> + <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true" /> + <option name="instrumentation-arg" key="perfetto_config_file" value="trace_config.textproto" /> + + <option name="instrumentation-arg" key="newRunListenerMode" value="true" /> </test> </configuration> diff --git a/apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java b/apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java index c276ae1fe45e..6e644ffb8b27 100644 --- a/apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java +++ b/apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java @@ -168,7 +168,9 @@ public final class SearchSpec { /** Sets the maximum number of results to retrieve from the query */ @NonNull public SearchSpec.Builder setNumToRetrieve(int numToRetrieve) { - mResultSpecBuilder.setNumToRetrieve(numToRetrieve); + // Just retrieve everything in one page. + // TODO(b/152359656): Realign these two apis properly. + mResultSpecBuilder.setNumPerPage(numToRetrieve); return this; } diff --git a/api/current.txt b/api/current.txt index 69700f3b0a60..532c3d938334 100644 --- a/api/current.txt +++ b/api/current.txt @@ -45976,7 +45976,9 @@ package android.telecom { method public final void addExistingConnection(android.telecom.PhoneAccountHandle, android.telecom.Connection); method public final void conferenceRemoteConnections(android.telecom.RemoteConnection, android.telecom.RemoteConnection); method public final void connectionServiceFocusReleased(); + method @Nullable public final android.telecom.RemoteConference createRemoteIncomingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest); method public final android.telecom.RemoteConnection createRemoteIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); + method @Nullable public final android.telecom.RemoteConference createRemoteOutgoingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest); method public final android.telecom.RemoteConnection createRemoteOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); method public final java.util.Collection<android.telecom.Conference> getAllConferences(); method public final java.util.Collection<android.telecom.Connection> getAllConnections(); @@ -46207,6 +46209,7 @@ package android.telecom { public final class RemoteConnection { method public void abort(); + method public void addConferenceParticipants(@NonNull java.util.List<android.net.Uri>); method public void answer(); method public void disconnect(); method public android.net.Uri getAddress(); @@ -65724,7 +65727,7 @@ package java.lang.reflect { package java.math { - public class BigDecimal extends java.lang.Number implements java.lang.Comparable<java.math.BigDecimal> java.io.Serializable { + public class BigDecimal extends java.lang.Number implements java.lang.Comparable<java.math.BigDecimal> { ctor public BigDecimal(char[], int, int); ctor public BigDecimal(char[], int, int, java.math.MathContext); ctor public BigDecimal(char[]); @@ -65811,19 +65814,20 @@ package java.math { field public static final java.math.BigDecimal ZERO; } - public class BigInteger extends java.lang.Number implements java.lang.Comparable<java.math.BigInteger> java.io.Serializable { + public class BigInteger extends java.lang.Number implements java.lang.Comparable<java.math.BigInteger> { + ctor public BigInteger(byte[]); + ctor public BigInteger(int, byte[]); + ctor public BigInteger(@NonNull String, int); + ctor public BigInteger(@NonNull String); ctor public BigInteger(int, @NonNull java.util.Random); ctor public BigInteger(int, int, @NonNull java.util.Random); - ctor public BigInteger(@NonNull String); - ctor public BigInteger(@NonNull String, int); - ctor public BigInteger(int, byte[]); - ctor public BigInteger(byte[]); method @NonNull public java.math.BigInteger abs(); method @NonNull public java.math.BigInteger add(@NonNull java.math.BigInteger); method @NonNull public java.math.BigInteger and(@NonNull java.math.BigInteger); method @NonNull public java.math.BigInteger andNot(@NonNull java.math.BigInteger); method public int bitCount(); method public int bitLength(); + method public byte byteValueExact(); method @NonNull public java.math.BigInteger clearBit(int); method public int compareTo(@NonNull java.math.BigInteger); method @NonNull public java.math.BigInteger divide(@NonNull java.math.BigInteger); @@ -65834,8 +65838,10 @@ package java.math { method @NonNull public java.math.BigInteger gcd(@NonNull java.math.BigInteger); method public int getLowestSetBit(); method public int intValue(); + method public int intValueExact(); method public boolean isProbablePrime(int); method public long longValue(); + method public long longValueExact(); method @NonNull public java.math.BigInteger max(@NonNull java.math.BigInteger); method @NonNull public java.math.BigInteger min(@NonNull java.math.BigInteger); method @NonNull public java.math.BigInteger mod(@NonNull java.math.BigInteger); @@ -65852,6 +65858,7 @@ package java.math { method @NonNull public java.math.BigInteger setBit(int); method @NonNull public java.math.BigInteger shiftLeft(int); method @NonNull public java.math.BigInteger shiftRight(int); + method public short shortValueExact(); method public int signum(); method @NonNull public java.math.BigInteger subtract(@NonNull java.math.BigInteger); method public boolean testBit(int); diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt index b587ea1f3b74..7cd8a628c9fc 100644 --- a/api/module-lib-current.txt +++ b/api/module-lib-current.txt @@ -7,6 +7,7 @@ package android.app { public class NotificationManager { method public boolean hasEnabledNotificationListener(@NonNull String, @NonNull android.os.UserHandle); + field public static final String ACTION_NOTIFICATION_LISTENER_ENABLED_CHANGED = "android.app.action.NOTIFICATION_LISTENER_ENABLED_CHANGED"; } } diff --git a/api/system-current.txt b/api/system-current.txt index 721523c95ecb..ea16238316ac 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4196,7 +4196,8 @@ package android.media { public class AudioManager { method @Deprecated public int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes); - method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDeviceForStrategyChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener) throws java.lang.SecurityException; + method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDeviceForStrategyChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener) throws java.lang.SecurityException; + method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDevicesForStrategyChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDevicesForStrategyChangedListener) throws java.lang.SecurityException; method public void clearAudioServerStateCallback(); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int dispatchAudioFocusChange(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy); method @IntRange(from=0) public long getAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo); @@ -4208,13 +4209,15 @@ package android.media { method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMinVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.AudioDeviceAttributes getPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy); + method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAttributes> getPreferredDevicesForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int[] getSupportedSystemUsages(); method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); method public boolean isAudioServerRunning(); method public boolean isHdmiSystemAudioSupported(); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int registerAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy); method public void registerVolumeGroupCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.VolumeGroupCallback); - method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDeviceForStrategyChangedListener(@NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener); + method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDeviceForStrategyChangedListener(@NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener); + method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDevicesForStrategyChangedListener(@NonNull android.media.AudioManager.OnPreferredDevicesForStrategyChangedListener); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean removePreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int) throws java.lang.IllegalArgumentException; method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.MODIFY_AUDIO_ROUTING}) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int, android.media.audiopolicy.AudioPolicy) throws java.lang.IllegalArgumentException; @@ -4224,6 +4227,7 @@ package android.media { method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes, int); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull android.media.AudioDeviceAttributes); + method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDevicesForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull java.util.List<android.media.AudioDeviceAttributes>); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setSupportedSystemUsages(@NonNull int[]); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setVolumeIndexForAttributes(@NonNull android.media.AudioAttributes, int, int); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy); @@ -4247,8 +4251,12 @@ package android.media { method public void onAudioServerUp(); } - public static interface AudioManager.OnPreferredDeviceForStrategyChangedListener { - method public void onPreferredDeviceForStrategyChanged(@NonNull android.media.audiopolicy.AudioProductStrategy, @Nullable android.media.AudioDeviceAttributes); + @Deprecated public static interface AudioManager.OnPreferredDeviceForStrategyChangedListener { + method @Deprecated public void onPreferredDeviceForStrategyChanged(@NonNull android.media.audiopolicy.AudioProductStrategy, @Nullable android.media.AudioDeviceAttributes); + } + + public static interface AudioManager.OnPreferredDevicesForStrategyChangedListener { + method public void onPreferredDevicesForStrategyChanged(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull java.util.List<android.media.AudioDeviceAttributes>); } public abstract static class AudioManager.VolumeGroupCallback { diff --git a/api/test-current.txt b/api/test-current.txt index 3332525a6647..10a367fa9267 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -1780,6 +1780,9 @@ package android.media { method public static float getMasterBalance(); method public static final int getNumStreamTypes(); method public static int setMasterBalance(float); + field public static final int DEVICE_ROLE_DISABLED = 2; // 0x2 + field public static final int DEVICE_ROLE_NONE = 0; // 0x0 + field public static final int DEVICE_ROLE_PREFERRED = 1; // 0x1 field public static final int STREAM_DEFAULT = -1; // 0xffffffff } diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index c95f4c07f86c..6b335ee1b923 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -4434,15 +4434,12 @@ message PrivacyIndicatorsInteracted { UNKNOWN = 0; CHIP_VIEWED = 1; CHIP_CLICKED = 2; - DIALOG_PRIVACY_SETTINGS = 3; + reserved 3; // Used only in beta builds, never shipped DIALOG_DISMISS = 4; DIALOG_LINE_ITEM = 5; } optional Type type = 1 [(state_field_option).exclusive_state = true]; - - // Used if the type is LINE_ITEM - optional string package_name = 2; } /** diff --git a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp index 52ef95d19cdc..9d3943fe8260 100644 --- a/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp +++ b/cmds/statsd/src/metrics/parsing_utils/metrics_manager_util.cpp @@ -148,8 +148,6 @@ bool handleMetricWithConditions( ALOGW("cannot find Predicate \"%lld\" in the config", (long long)link.condition()); return false; } - allConditionTrackers[condition_it->second]->setSliced(true); - allConditionTrackers[it->second]->setSliced(true); } conditionIndex = condition_it->second; diff --git a/config/boot-image-profile.txt b/config/boot-image-profile.txt index ab2f42b97e3b..f43bd2bd61b9 100644 --- a/config/boot-image-profile.txt +++ b/config/boot-image-profile.txt @@ -33629,6 +33629,35 @@ HSPLjava/math/BigInteger;-><init>([B)V HSPLjava/math/BigInteger;->abs()Ljava/math/BigInteger; HSPLjava/math/BigInteger;->add(Ljava/math/BigInteger;)Ljava/math/BigInteger; HSPLjava/math/BigInteger;->bitLength()I +#Temporary manual additions to avoid slowing tests down too much +#Carefully positioned for clean merge +HSPLjava/math/BigInteger;->add([IJ)[I +HSPLjava/math/BigInteger;->add([I[I)[I +HSPLjava/math/BigInteger;->subtract([IJ)[I +HSPLjava/math/BigInteger;->subtract([I[I)[I +HSPLjava/math/BigInteger;->jacobiSymbol(ILjava/math/BigInteger;)I +HSPLjava/math/BigInteger;->lucasLehmerSequence(ILjava/math/BigInteger;Ljava/math/BigInteger;)Ljava/math/BigInteger; +HSPLjava/math/BigInteger;->multiplyToLen([II[II[I)[I +HSPLjava/math/MutableBigInteger;->add(Ljava/math/MutableBigInteger;)V +HSPLjava/math/MutableBigInteger;->addShifted(Ljava/math/MutableBigInteger;)V +HSPLjava/math/MutableBigInteger;->subtract(Ljava/math/MutableBigInteger;)V +HSPLjava/math/MutableBigInteger;->difference(Ljava/math/MutableBigInteger;)V +HSPLjava/math/MutableBigInteger;->divideKnuth(Ljava/math/MutableBigInteger;Ljava/math/MutableBigInteger;Z)Ljava/math/MutableBigInteger; +HSPLjava/math/MutableBigInteger;->divideMagnitude(Ljava/math/MutableBigInteger;Ljava/math/MutableBigInteger;Z)Ljava/math/MutableBigInteger; +HSPLjava/math/MutableBigInteger;->divideLongMagnitude(JLjava/math/MutableBigInteger;)Ljava/math/MutableBigInteger; +HSPLjava/math/MutableBigInteger;->divideOneWord(ILjava/math/MutableBigInteger;)I +HSPLjava/math/MutableBigInteger;->divadd([I[II)I +HSPLjava/math/MutableBigInteger;->mulsub([I[IIII)I +HSPLjava/math/MutableBigInteger;->mulsubBorrow([I[IIII)I +HSPLjava/math/MutableBigInteger;->copyAndShift([III[III)V +HSPLjava/math/MutableBigInteger;->multiply(Ljava/math/MutableBigInteger;Ljava/math/MutableBigInteger;)V +HSPLjava/math/MutableBigInteger;->mul(ILjava/math/MutableBigInteger;)V +HSPLjava/math/MutableBigInteger;->multiply(ILjava/math/MutableBigInteger;)V +HSPLjava/math/MutableBigInteger;->primitiveRightShift(I)I +HSPLjava/math/MutableBigInteger;->primitiveLeftShift(I)I +HSPLjava/math/MutableBigInteger;->binaryGCD(Ljava/math/MutableBigInteger;)Ljava/math/MutableBigInteger; +HSPLjava/math/MutableBigInteger;->binaryGCD(II)I +#End of maual additions HSPLjava/math/BigInteger;->compareTo(Ljava/math/BigInteger;)I HSPLjava/math/BigInteger;->divide(Ljava/math/BigInteger;)Ljava/math/BigInteger; HSPLjava/math/BigInteger;->divideAndRemainder(Ljava/math/BigInteger;)[Ljava/math/BigInteger; diff --git a/config/preloaded-classes b/config/preloaded-classes index e43c7d42868c..f56656b69ec4 100644 --- a/config/preloaded-classes +++ b/config/preloaded-classes @@ -3709,9 +3709,9 @@ android.media.IRemoteVolumeObserver android.media.IRingtonePlayer$Stub$Proxy android.media.IRingtonePlayer$Stub android.media.IRingtonePlayer -android.media.IStrategyPreferredDeviceDispatcher$Stub$Proxy -android.media.IStrategyPreferredDeviceDispatcher$Stub -android.media.IStrategyPreferredDeviceDispatcher +android.media.IStrategyPreferredDevicesDispatcher$Stub$Proxy +android.media.IStrategyPreferredDevicesDispatcher$Stub +android.media.IStrategyPreferredDevicesDispatcher android.media.IVolumeController$Stub$Proxy android.media.IVolumeController$Stub android.media.IVolumeController diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index d67b98620f37..267b81823688 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -614,7 +614,7 @@ public final class ActivityThread extends ClientTransactionHandler { throw new IllegalStateException( "Received config update for non-existing activity"); } - activity.mMainThread.handleActivityConfigurationChanged(token, overrideConfig, + activity.mMainThread.handleActivityConfigurationChanged(this, overrideConfig, newDisplayId); }; } @@ -3475,13 +3475,9 @@ public final class ActivityThread extends ClientTransactionHandler { } @Override - public void handleStartActivity(IBinder token, PendingTransactionActions pendingActions) { - final ActivityClientRecord r = mActivities.get(token); + public void handleStartActivity(ActivityClientRecord r, + PendingTransactionActions pendingActions) { final Activity activity = r.activity; - if (r.activity == null) { - // TODO(lifecycler): What do we do in this case? - return; - } if (!r.stopped) { throw new IllegalStateException("Can't start activity that is not stopped."); } @@ -3687,12 +3683,7 @@ public final class ActivityThread extends ClientTransactionHandler { } @Override - public void handleNewIntent(IBinder token, List<ReferrerIntent> intents) { - final ActivityClientRecord r = mActivities.get(token); - if (r == null) { - return; - } - + public void handleNewIntent(ActivityClientRecord r, List<ReferrerIntent> intents) { checkAndBlockForNetworkAccess(); deliverNewIntents(r, intents); } @@ -3881,13 +3872,7 @@ public final class ActivityThread extends ClientTransactionHandler { } @Override - public void handlePictureInPictureRequested(IBinder token) { - final ActivityClientRecord r = mActivities.get(token); - if (r == null) { - Log.w(TAG, "Activity to request PIP to no longer exists"); - return; - } - + public void handlePictureInPictureRequested(ActivityClientRecord r) { final boolean receivedByApp = r.activity.onPictureInPictureRequested(); if (!receivedByApp) { // Previous recommendation was for apps to enter picture-in-picture in @@ -4417,22 +4402,21 @@ public final class ActivityThread extends ClientTransactionHandler { /** * Resume the activity. - * @param token Target activity token. + * @param r Target activity record. * @param finalStateRequest Flag indicating if this is part of final state resolution for a * transaction. * @param reason Reason for performing the action. * - * @return The {@link ActivityClientRecord} that was resumed, {@code null} otherwise. + * @return {@code true} that was resumed, {@code false} otherwise. */ @VisibleForTesting - public ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest, + public boolean performResumeActivity(ActivityClientRecord r, boolean finalStateRequest, String reason) { - final ActivityClientRecord r = mActivities.get(token); if (localLOGV) { Slog.v(TAG, "Performing resume of " + r + " finished=" + r.activity.mFinished); } - if (r == null || r.activity.mFinished) { - return null; + if (r.activity.mFinished) { + return false; } if (r.getLifecycleState() == ON_RESUME) { if (!finalStateRequest) { @@ -4446,7 +4430,7 @@ public final class ActivityThread extends ClientTransactionHandler { // handle two resume requests for the final state. For cases other than this // one, we don't expect it to happen. } - return null; + return false; } if (finalStateRequest) { r.hideForNow = false; @@ -4477,7 +4461,7 @@ public final class ActivityThread extends ClientTransactionHandler { + r.intent.getComponent().toShortString() + ": " + e.toString(), e); } } - return r; + return true; } static final void cleanUpPendingRemoveWindows(ActivityClientRecord r, boolean force) { @@ -4498,20 +4482,19 @@ public final class ActivityThread extends ClientTransactionHandler { } @Override - public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward, - String reason) { + public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest, + boolean isForward, String reason) { // If we are getting ready to gc after going to the background, well // we are back active so skip it. unscheduleGcIdler(); mSomeActivitiesChanged = true; // TODO Push resumeArgs into the activity for consideration - final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason); - if (r == null) { - // We didn't actually resume the activity, so skipping any follow-up actions. + // skip below steps for double-resume and r.mFinish = true case. + if (!performResumeActivity(r, finalStateRequest, reason)) { return; } - if (mActivitiesToBeDestroyed.containsKey(token)) { + if (mActivitiesToBeDestroyed.containsKey(r.token)) { // Although the activity is resumed, it is going to be destroyed. So the following // UI operations are unnecessary and also prevents exception because its token may // be gone that window manager cannot recognize it. All necessary cleanup actions @@ -4629,13 +4612,8 @@ public final class ActivityThread extends ClientTransactionHandler { @Override - public void handleTopResumedActivityChanged(IBinder token, boolean onTop, String reason) { - ActivityClientRecord r = mActivities.get(token); - if (r == null || r.activity == null) { - Slog.w(TAG, "Not found target activity to report position change for token: " + token); - return; - } - + public void handleTopResumedActivityChanged(ActivityClientRecord r, boolean onTop, + String reason) { if (DEBUG_ORDER) { Slog.d(TAG, "Received position change to top: " + onTop + " for activity: " + r); } @@ -4668,23 +4646,20 @@ public final class ActivityThread extends ClientTransactionHandler { } @Override - public void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving, + public void handlePauseActivity(ActivityClientRecord r, boolean finished, boolean userLeaving, int configChanges, PendingTransactionActions pendingActions, String reason) { - ActivityClientRecord r = mActivities.get(token); - if (r != null) { - if (userLeaving) { - performUserLeavingActivity(r); - } + if (userLeaving) { + performUserLeavingActivity(r); + } - r.activity.mConfigChangeFlags |= configChanges; - performPauseActivity(r, finished, reason, pendingActions); + r.activity.mConfigChangeFlags |= configChanges; + performPauseActivity(r, finished, reason, pendingActions); - // Make sure any pending writes are now committed. - if (r.isPreHoneycomb()) { - QueuedWork.waitToFinish(); - } - mSomeActivitiesChanged = true; + // Make sure any pending writes are now committed. + if (r.isPreHoneycomb()) { + QueuedWork.waitToFinish(); } + mSomeActivitiesChanged = true; } final void performUserLeavingActivity(ActivityClientRecord r) { @@ -4781,8 +4756,11 @@ public final class ActivityThread extends ClientTransactionHandler { r.setState(ON_PAUSE); } + // TODO(b/127877792): Make LocalActivityManager call performStopActivityInner. We cannot do this + // since it's a high usage hidden API. /** Called from {@link LocalActivityManager}. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 127877792, + publicAlternatives = "{@code N/A}") final void performStopActivity(IBinder token, boolean saveState, String reason) { ActivityClientRecord r = mActivities.get(token); performStopActivityInner(r, null /* stopInfo */, saveState, false /* finalStateRequest */, @@ -4823,39 +4801,37 @@ public final class ActivityThread extends ClientTransactionHandler { private void performStopActivityInner(ActivityClientRecord r, StopInfo info, boolean saveState, boolean finalStateRequest, String reason) { if (localLOGV) Slog.v(TAG, "Performing stop of " + r); - if (r != null) { - if (r.stopped) { - if (r.activity.mFinished) { - // If we are finishing, we won't call onResume() in certain - // cases. So here we likewise don't want to call onStop() - // if the activity isn't resumed. - return; - } - if (!finalStateRequest) { - final RuntimeException e = new RuntimeException( - "Performing stop of activity that is already stopped: " - + r.intent.getComponent().toShortString()); - Slog.e(TAG, e.getMessage(), e); - Slog.e(TAG, r.getStateString()); - } + if (r.stopped) { + if (r.activity.mFinished) { + // If we are finishing, we won't call onResume() in certain + // cases. So here we likewise don't want to call onStop() + // if the activity isn't resumed. + return; + } + if (!finalStateRequest) { + final RuntimeException e = new RuntimeException( + "Performing stop of activity that is already stopped: " + + r.intent.getComponent().toShortString()); + Slog.e(TAG, e.getMessage(), e); + Slog.e(TAG, r.getStateString()); } + } - // One must first be paused before stopped... - performPauseActivityIfNeeded(r, reason); + // One must first be paused before stopped... + performPauseActivityIfNeeded(r, reason); - if (info != null) { - try { - // First create a thumbnail for the activity... - // For now, don't create the thumbnail here; we are - // doing that by doing a screen snapshot. - info.setDescription(r.activity.onCreateDescription()); - } catch (Exception e) { - if (!mInstrumentation.onException(r.activity, e)) { - throw new RuntimeException( - "Unable to save state of activity " - + r.intent.getComponent().toShortString() - + ": " + e.toString(), e); - } + if (info != null) { + try { + // First create a thumbnail for the activity... + // For now, don't create the thumbnail here; we are + // doing that by doing a screen snapshot. + info.setDescription(r.activity.onCreateDescription()); + } catch (Exception e) { + if (!mInstrumentation.onException(r.activity, e)) { + throw new RuntimeException( + "Unable to save state of activity " + + r.intent.getComponent().toShortString() + + ": " + e.toString(), e); } } @@ -4927,9 +4903,8 @@ public final class ActivityThread extends ClientTransactionHandler { } @Override - public void handleStopActivity(IBinder token, int configChanges, + public void handleStopActivity(ActivityClientRecord r, int configChanges, PendingTransactionActions pendingActions, boolean finalStateRequest, String reason) { - final ActivityClientRecord r = mActivities.get(token); r.activity.mConfigChangeFlags |= configChanges; final StopInfo stopInfo = new StopInfo(); @@ -4965,8 +4940,7 @@ public final class ActivityThread extends ClientTransactionHandler { } @Override - public void performRestartActivity(IBinder token, boolean start) { - ActivityClientRecord r = mActivities.get(token); + public void performRestartActivity(ActivityClientRecord r, boolean start) { if (r.stopped) { r.activity.performRestart(start, "performRestartActivity"); if (start) { @@ -5053,107 +5027,101 @@ public final class ActivityThread extends ClientTransactionHandler { } @Override - public void handleSendResult(IBinder token, List<ResultInfo> results, String reason) { - ActivityClientRecord r = mActivities.get(token); + public void handleSendResult(ActivityClientRecord r, List<ResultInfo> results, String reason) { if (DEBUG_RESULTS) Slog.v(TAG, "Handling send result to " + r); - if (r != null) { - final boolean resumed = !r.paused; - if (!r.activity.mFinished && r.activity.mDecor != null - && r.hideForNow && resumed) { - // We had hidden the activity because it started another - // one... we have gotten a result back and we are not - // paused, so make sure our window is visible. - updateVisibility(r, true); - } - if (resumed) { - try { - // Now we are idle. - r.activity.mCalled = false; - mInstrumentation.callActivityOnPause(r.activity); - if (!r.activity.mCalled) { - throw new SuperNotCalledException( - "Activity " + r.intent.getComponent().toShortString() - + " did not call through to super.onPause()"); - } - } catch (SuperNotCalledException e) { - throw e; - } catch (Exception e) { - if (!mInstrumentation.onException(r.activity, e)) { - throw new RuntimeException( - "Unable to pause activity " - + r.intent.getComponent().toShortString() - + ": " + e.toString(), e); - } + final boolean resumed = !r.paused; + if (!r.activity.mFinished && r.activity.mDecor != null + && r.hideForNow && resumed) { + // We had hidden the activity because it started another + // one... we have gotten a result back and we are not + // paused, so make sure our window is visible. + updateVisibility(r, true); + } + if (resumed) { + try { + // Now we are idle. + r.activity.mCalled = false; + mInstrumentation.callActivityOnPause(r.activity); + if (!r.activity.mCalled) { + throw new SuperNotCalledException( + "Activity " + r.intent.getComponent().toShortString() + + " did not call through to super.onPause()"); + } + } catch (SuperNotCalledException e) { + throw e; + } catch (Exception e) { + if (!mInstrumentation.onException(r.activity, e)) { + throw new RuntimeException( + "Unable to pause activity " + + r.intent.getComponent().toShortString() + + ": " + e.toString(), e); } - } - checkAndBlockForNetworkAccess(); - deliverResults(r, results, reason); - if (resumed) { - r.activity.performResume(false, reason); } } + checkAndBlockForNetworkAccess(); + deliverResults(r, results, reason); + if (resumed) { + r.activity.performResume(false, reason); + } } /** Core implementation of activity destroy call. */ - ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing, + ActivityClientRecord performDestroyActivity(ActivityClientRecord r, boolean finishing, int configChanges, boolean getNonConfigInstance, String reason) { - ActivityClientRecord r = mActivities.get(token); Class<? extends Activity> activityClass = null; if (localLOGV) Slog.v(TAG, "Performing finish of " + r); - if (r != null) { - activityClass = r.activity.getClass(); - r.activity.mConfigChangeFlags |= configChanges; - if (finishing) { - r.activity.mFinished = true; - } + activityClass = r.activity.getClass(); + r.activity.mConfigChangeFlags |= configChanges; + if (finishing) { + r.activity.mFinished = true; + } - performPauseActivityIfNeeded(r, "destroy"); + performPauseActivityIfNeeded(r, "destroy"); - if (!r.stopped) { - callActivityOnStop(r, false /* saveState */, "destroy"); - } - if (getNonConfigInstance) { - try { - r.lastNonConfigurationInstances - = r.activity.retainNonConfigurationInstances(); - } catch (Exception e) { - if (!mInstrumentation.onException(r.activity, e)) { - throw new RuntimeException( - "Unable to retain activity " - + r.intent.getComponent().toShortString() - + ": " + e.toString(), e); - } - } - } + if (!r.stopped) { + callActivityOnStop(r, false /* saveState */, "destroy"); + } + if (getNonConfigInstance) { try { - r.activity.mCalled = false; - mInstrumentation.callActivityOnDestroy(r.activity); - if (!r.activity.mCalled) { - throw new SuperNotCalledException( - "Activity " + safeToComponentShortString(r.intent) + - " did not call through to super.onDestroy()"); - } - if (r.window != null) { - r.window.closeAllPanels(); - } - } catch (SuperNotCalledException e) { - throw e; + r.lastNonConfigurationInstances = r.activity.retainNonConfigurationInstances(); } catch (Exception e) { if (!mInstrumentation.onException(r.activity, e)) { throw new RuntimeException( - "Unable to destroy activity " + safeToComponentShortString(r.intent) + "Unable to retain activity " + + r.intent.getComponent().toShortString() + ": " + e.toString(), e); } } r.setState(ON_DESTROY); mLastReportedWindowingMode.remove(r.activity.getActivityToken()); } + try { + r.activity.mCalled = false; + mInstrumentation.callActivityOnDestroy(r.activity); + if (!r.activity.mCalled) { + throw new SuperNotCalledException( + "Activity " + safeToComponentShortString(r.intent) + + " did not call through to super.onDestroy()"); + } + if (r.window != null) { + r.window.closeAllPanels(); + } + } catch (SuperNotCalledException e) { + throw e; + } catch (Exception e) { + if (!mInstrumentation.onException(r.activity, e)) { + throw new RuntimeException( + "Unable to destroy activity " + safeToComponentShortString(r.intent) + + ": " + e.toString(), e); + } + } + r.setState(ON_DESTROY); schedulePurgeIdler(); // updatePendingActivityConfiguration() reads from mActivities to update // ActivityClientRecord which runs in a different thread. Protect modifications to // mActivities to avoid race. synchronized (mResourcesManager) { - mActivities.remove(token); + mActivities.remove(r.token); } StrictMode.decrementExpectedActivityCount(activityClass); return r; @@ -5170,70 +5138,67 @@ public final class ActivityThread extends ClientTransactionHandler { } @Override - public void handleDestroyActivity(IBinder token, boolean finishing, int configChanges, + public void handleDestroyActivity(ActivityClientRecord r, boolean finishing, int configChanges, boolean getNonConfigInstance, String reason) { - ActivityClientRecord r = performDestroyActivity(token, finishing, - configChanges, getNonConfigInstance, reason); - if (r != null) { - cleanUpPendingRemoveWindows(r, finishing); - WindowManager wm = r.activity.getWindowManager(); - View v = r.activity.mDecor; - if (v != null) { - if (r.activity.mVisibleFromServer) { - mNumVisibleActivities--; - } - IBinder wtoken = v.getWindowToken(); - if (r.activity.mWindowAdded) { - if (r.mPreserveWindow) { - // Hold off on removing this until the new activity's - // window is being added. - r.mPendingRemoveWindow = r.window; - r.mPendingRemoveWindowManager = wm; - // We can only keep the part of the view hierarchy that we control, - // everything else must be removed, because it might not be able to - // behave properly when activity is relaunching. - r.window.clearContentView(); - } else { - wm.removeViewImmediate(v); - } - } - if (wtoken != null && r.mPendingRemoveWindow == null) { - WindowManagerGlobal.getInstance().closeAll(wtoken, - r.activity.getClass().getName(), "Activity"); - } else if (r.mPendingRemoveWindow != null) { - // We're preserving only one window, others should be closed so app views - // will be detached before the final tear down. It should be done now because - // some components (e.g. WebView) rely on detach callbacks to perform receiver - // unregister and other cleanup. - WindowManagerGlobal.getInstance().closeAllExceptView(token, v, - r.activity.getClass().getName(), "Activity"); + r = performDestroyActivity(r, finishing, configChanges, getNonConfigInstance, reason); + cleanUpPendingRemoveWindows(r, finishing); + WindowManager wm = r.activity.getWindowManager(); + View v = r.activity.mDecor; + if (v != null) { + if (r.activity.mVisibleFromServer) { + mNumVisibleActivities--; + } + IBinder wtoken = v.getWindowToken(); + if (r.activity.mWindowAdded) { + if (r.mPreserveWindow) { + // Hold off on removing this until the new activity's + // window is being added. + r.mPendingRemoveWindow = r.window; + r.mPendingRemoveWindowManager = wm; + // We can only keep the part of the view hierarchy that we control, + // everything else must be removed, because it might not be able to + // behave properly when activity is relaunching. + r.window.clearContentView(); + } else { + wm.removeViewImmediate(v); } - r.activity.mDecor = null; - } - if (r.mPendingRemoveWindow == null) { - // If we are delaying the removal of the activity window, then - // we can't clean up all windows here. Note that we can't do - // so later either, which means any windows that aren't closed - // by the app will leak. Well we try to warning them a lot - // about leaking windows, because that is a bug, so if they are - // using this recreate facility then they get to live with leaks. - WindowManagerGlobal.getInstance().closeAll(token, - r.activity.getClass().getName(), "Activity"); } - - // Mocked out contexts won't be participating in the normal - // process lifecycle, but if we're running with a proper - // ApplicationContext we need to have it tear down things - // cleanly. - Context c = r.activity.getBaseContext(); - if (c instanceof ContextImpl) { - ((ContextImpl) c).scheduleFinalCleanup( + if (wtoken != null && r.mPendingRemoveWindow == null) { + WindowManagerGlobal.getInstance().closeAll(wtoken, + r.activity.getClass().getName(), "Activity"); + } else if (r.mPendingRemoveWindow != null) { + // We're preserving only one window, others should be closed so app views + // will be detached before the final tear down. It should be done now because + // some components (e.g. WebView) rely on detach callbacks to perform receiver + // unregister and other cleanup. + WindowManagerGlobal.getInstance().closeAllExceptView(r.token, v, r.activity.getClass().getName(), "Activity"); } + r.activity.mDecor = null; + } + if (r.mPendingRemoveWindow == null) { + // If we are delaying the removal of the activity window, then + // we can't clean up all windows here. Note that we can't do + // so later either, which means any windows that aren't closed + // by the app will leak. Well we try to warning them a lot + // about leaking windows, because that is a bug, so if they are + // using this recreate facility then they get to live with leaks. + WindowManagerGlobal.getInstance().closeAll(r.token, + r.activity.getClass().getName(), "Activity"); + } + + // Mocked out contexts won't be participating in the normal + // process lifecycle, but if we're running with a proper + // ApplicationContext we need to have it tear down things + // cleanly. + Context c = r.activity.getBaseContext(); + if (c instanceof ContextImpl) { + ((ContextImpl) c).scheduleFinalCleanup( + r.activity.getClass().getName(), "Activity"); } if (finishing) { try { - ActivityTaskManager.getService().activityDestroyed(token); + ActivityTaskManager.getService().activityDestroyed(r.token); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } @@ -5456,7 +5421,7 @@ public final class ActivityThread extends ClientTransactionHandler { callActivityOnStop(r, true /* saveState */, reason); } - handleDestroyActivity(r.token, false, configChanges, true, reason); + handleDestroyActivity(r, false, configChanges, true, reason); r.activity = null; r.window = null; @@ -5484,12 +5449,10 @@ public final class ActivityThread extends ClientTransactionHandler { } @Override - public void reportRelaunch(IBinder token, PendingTransactionActions pendingActions) { + public void reportRelaunch(ActivityClientRecord r, PendingTransactionActions pendingActions) { try { - ActivityTaskManager.getService().activityRelaunched(token); - final ActivityClientRecord r = mActivities.get(token); - if (pendingActions.shouldReportRelaunchToWindowManager() && r != null - && r.window != null) { + ActivityTaskManager.getService().activityRelaunched(r.token); + if (pendingActions.shouldReportRelaunchToWindowManager() && r.window != null) { r.window.reportActivityRelaunched(); } } catch (RemoteException e) { @@ -5648,13 +5611,7 @@ public final class ActivityThread extends ClientTransactionHandler { */ private Configuration performActivityConfigurationChanged(Activity activity, Configuration newConfig, Configuration amOverrideConfig, int displayId) { - if (activity == null) { - throw new IllegalArgumentException("No activity provided."); - } final IBinder activityToken = activity.getActivityToken(); - if (activityToken == null) { - throw new IllegalArgumentException("Activity token not set. Is the activity attached?"); - } final boolean movedToDifferentDisplay = isDifferentDisplay(activity, displayId); boolean shouldReportChange = false; @@ -5954,20 +5911,8 @@ public final class ActivityThread extends ClientTransactionHandler { * processing any configurations older than {@code overrideConfig}. */ @Override - public void updatePendingActivityConfiguration(IBinder activityToken, + public void updatePendingActivityConfiguration(ActivityClientRecord r, Configuration overrideConfig) { - final ActivityClientRecord r; - synchronized (mResourcesManager) { - r = mActivities.get(activityToken); - } - - if (r == null) { - if (DEBUG_CONFIGURATION) { - Slog.w(TAG, "Not found target activity to update its pending config."); - } - return; - } - synchronized (r) { if (r.mPendingOverrideConfig != null && !r.mPendingOverrideConfig.isOtherSeqNewer(overrideConfig)) { @@ -5987,21 +5932,14 @@ public final class ActivityThread extends ClientTransactionHandler { * if {@link #updatePendingActivityConfiguration(IBinder, Configuration)} has been called with * a newer config than {@code overrideConfig}. * - * @param activityToken Target activity token. + * @param r Target activity record. * @param overrideConfig Activity override config. * @param displayId Id of the display where activity was moved to, -1 if there was no move and * value didn't change. */ @Override - public void handleActivityConfigurationChanged(IBinder activityToken, + public void handleActivityConfigurationChanged(ActivityClientRecord r, @NonNull Configuration overrideConfig, int displayId) { - ActivityClientRecord r = mActivities.get(activityToken); - // Check input params. - if (r == null || r.activity == null) { - if (DEBUG_CONFIGURATION) Slog.w(TAG, "Not found target activity to report to: " + r); - return; - } - synchronized (r) { if (overrideConfig.isOtherSeqNewer(r.mPendingOverrideConfig)) { if (DEBUG_CONFIGURATION) { diff --git a/core/java/android/app/ApplicationLoaders.java b/core/java/android/app/ApplicationLoaders.java index 15237beee805..08cd0b34ee0a 100644 --- a/core/java/android/app/ApplicationLoaders.java +++ b/core/java/android/app/ApplicationLoaders.java @@ -243,8 +243,8 @@ public class ApplicationLoaders { // cached must be built and loaded in the same environment if (!sharedLibrariesEquals(sharedLibraries, cached.sharedLibraries)) { - Log.w(TAG, "Unexpected environment for cached library: (" + sharedLibraries + "|" - + cached.sharedLibraries + ")"); + Log.w(TAG, "Unexpected environment loading cached library " + zip + " (real|cached): (" + + sharedLibraries + "|" + cached.sharedLibraries + ")"); return null; } diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index dedd8705ef55..676c6c01d349 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -684,8 +684,7 @@ public class ApplicationPackageManager extends PackageManager { @Override public int checkPermission(String permName, String pkgName) { - return PermissionManager - .checkPackageNamePermission(permName, pkgName, getUserId()); + return PermissionManager.checkPackageNamePermission(permName, pkgName, getUserId()); } @Override diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java index 2df756e80fde..ac50676ff46b 100644 --- a/core/java/android/app/ClientTransactionHandler.java +++ b/core/java/android/app/ClientTransactionHandler.java @@ -15,6 +15,8 @@ */ package android.app; +import android.annotation.NonNull; +import android.app.ActivityThread.ActivityClientRecord; import android.app.servertransaction.ClientTransaction; import android.app.servertransaction.ClientTransactionItem; import android.app.servertransaction.PendingTransactionActions; @@ -89,37 +91,38 @@ public abstract class ClientTransactionHandler { public abstract Map<IBinder, ClientTransactionItem> getActivitiesToBeDestroyed(); /** Destroy the activity. */ - public abstract void handleDestroyActivity(IBinder token, boolean finishing, int configChanges, - boolean getNonConfigInstance, String reason); + public abstract void handleDestroyActivity(@NonNull ActivityClientRecord r, boolean finishing, + int configChanges, boolean getNonConfigInstance, String reason); /** Pause the activity. */ - public abstract void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving, - int configChanges, PendingTransactionActions pendingActions, String reason); + public abstract void handlePauseActivity(@NonNull ActivityClientRecord r, boolean finished, + boolean userLeaving, int configChanges, PendingTransactionActions pendingActions, + String reason); /** * Resume the activity. - * @param token Target activity token. + * @param r Target activity record. * @param finalStateRequest Flag indicating if this call is handling final lifecycle state * request for a transaction. * @param isForward Flag indicating if next transition is forward. * @param reason Reason for performing this operation. */ - public abstract void handleResumeActivity(IBinder token, boolean finalStateRequest, - boolean isForward, String reason); + public abstract void handleResumeActivity(@NonNull ActivityClientRecord r, + boolean finalStateRequest, boolean isForward, String reason); /** * Notify the activity about top resumed state change. - * @param token Target activity token. + * @param r Target activity record. * @param isTopResumedActivity Current state of the activity, {@code true} if it's the * topmost resumed activity in the system, {@code false} otherwise. * @param reason Reason for performing this operation. */ - public abstract void handleTopResumedActivityChanged(IBinder token, + public abstract void handleTopResumedActivityChanged(@NonNull ActivityClientRecord r, boolean isTopResumedActivity, String reason); /** * Stop the activity. - * @param token Target activity token. + * @param r Target activity record. * @param configChanges Activity configuration changes. * @param pendingActions Pending actions to be used on this or later stages of activity * transaction. @@ -127,38 +130,40 @@ public abstract class ClientTransactionHandler { * request for a transaction. * @param reason Reason for performing this operation. */ - public abstract void handleStopActivity(IBinder token, int configChanges, + public abstract void handleStopActivity(@NonNull ActivityClientRecord r, int configChanges, PendingTransactionActions pendingActions, boolean finalStateRequest, String reason); /** Report that activity was stopped to server. */ public abstract void reportStop(PendingTransactionActions pendingActions); /** Restart the activity after it was stopped. */ - public abstract void performRestartActivity(IBinder token, boolean start); + public abstract void performRestartActivity(@NonNull ActivityClientRecord r, boolean start); /** Set pending activity configuration in case it will be updated by other transaction item. */ - public abstract void updatePendingActivityConfiguration(IBinder activityToken, + public abstract void updatePendingActivityConfiguration(@NonNull ActivityClientRecord r, Configuration overrideConfig); /** Deliver activity (override) configuration change. */ - public abstract void handleActivityConfigurationChanged(IBinder activityToken, + public abstract void handleActivityConfigurationChanged(@NonNull ActivityClientRecord r, Configuration overrideConfig, int displayId); /** Deliver result from another activity. */ - public abstract void handleSendResult(IBinder token, List<ResultInfo> results, String reason); + public abstract void handleSendResult( + @NonNull ActivityClientRecord r, List<ResultInfo> results, String reason); /** Deliver new intent. */ - public abstract void handleNewIntent(IBinder token, List<ReferrerIntent> intents); + public abstract void handleNewIntent( + @NonNull ActivityClientRecord r, List<ReferrerIntent> intents); /** Request that an activity enter picture-in-picture. */ - public abstract void handlePictureInPictureRequested(IBinder token); + public abstract void handlePictureInPictureRequested(@NonNull ActivityClientRecord r); /** Perform activity launch. */ - public abstract Activity handleLaunchActivity(ActivityThread.ActivityClientRecord r, + public abstract Activity handleLaunchActivity(@NonNull ActivityClientRecord r, PendingTransactionActions pendingActions, Intent customIntent); /** Perform activity start. */ - public abstract void handleStartActivity(IBinder token, + public abstract void handleStartActivity(@NonNull ActivityClientRecord r, PendingTransactionActions pendingActions); /** Get package info. */ @@ -176,7 +181,7 @@ public abstract class ClientTransactionHandler { * Get {@link android.app.ActivityThread.ActivityClientRecord} instance that corresponds to the * provided token. */ - public abstract ActivityThread.ActivityClientRecord getActivityClient(IBinder token); + public abstract ActivityClientRecord getActivityClient(IBinder token); /** * Prepare activity relaunch to update internal bookkeeping. This is used to track multiple @@ -191,7 +196,7 @@ public abstract class ClientTransactionHandler { * @return An initialized instance of {@link ActivityThread.ActivityClientRecord} to use during * relaunch, or {@code null} if relaunch cancelled. */ - public abstract ActivityThread.ActivityClientRecord prepareRelaunchActivity(IBinder token, + public abstract ActivityClientRecord prepareRelaunchActivity(IBinder token, List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents, int configChanges, MergedConfiguration config, boolean preserveWindow); @@ -200,14 +205,15 @@ public abstract class ClientTransactionHandler { * @param r Activity client record prepared for relaunch. * @param pendingActions Pending actions to be used on later stages of activity transaction. * */ - public abstract void handleRelaunchActivity(ActivityThread.ActivityClientRecord r, + public abstract void handleRelaunchActivity(@NonNull ActivityClientRecord r, PendingTransactionActions pendingActions); /** * Report that relaunch request was handled. - * @param token Target activity token. + * @param r Target activity record. * @param pendingActions Pending actions initialized on earlier stages of activity transaction. * Used to check if we should report relaunch to WM. * */ - public abstract void reportRelaunch(IBinder token, PendingTransactionActions pendingActions); + public abstract void reportRelaunch(@NonNull ActivityClientRecord r, + PendingTransactionActions pendingActions); } diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 93dfc79109a6..f37ca61ba69f 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -461,7 +461,7 @@ interface IActivityManager { @UnsupportedAppUsage Rect getTaskBounds(int taskId); @UnsupportedAppUsage - boolean setProcessMemoryTrimLevel(in String process, int uid, int level); + boolean setProcessMemoryTrimLevel(in String process, int userId, int level); // Start of L transactions diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java index 7cdf85e0a6b8..d61c5d5ccd3d 100644 --- a/core/java/android/app/LocalActivityManager.java +++ b/core/java/android/app/LocalActivityManager.java @@ -49,6 +49,7 @@ public class LocalActivityManager { private static final String TAG = "LocalActivityManager"; private static final boolean localLOGV = false; + // TODO(b/127877792): try to remove this and use {@code ActivityClientRecord} instead. // Internal token for an Activity being managed by LocalActivityManager. private static class LocalActivityRecord extends Binder { LocalActivityRecord(String _id, Intent _intent) { @@ -136,7 +137,7 @@ public class LocalActivityManager { // startActivity() has not yet been called, so nothing to do. return; } - + if (r.curState == INITIALIZING) { // Get the lastNonConfigurationInstance for the activity HashMap<String, Object> lastNonConfigurationInstances = @@ -177,12 +178,13 @@ public class LocalActivityManager { pendingActions = null; } - mActivityThread.handleStartActivity(r, pendingActions); + mActivityThread.handleStartActivity(clientRecord, pendingActions); r.curState = STARTED; if (desiredState == RESUMED) { if (localLOGV) Log.v(TAG, r.id + ": resuming"); - mActivityThread.performResumeActivity(r, true, "moveToState-INITIALIZING"); + mActivityThread.performResumeActivity(clientRecord, true, + "moveToState-INITIALIZING"); r.curState = RESUMED; } @@ -194,18 +196,21 @@ public class LocalActivityManager { // group's state catches up. return; } - + + final ActivityClientRecord clientRecord = mActivityThread.getActivityClient(r); + switch (r.curState) { case CREATED: if (desiredState == STARTED) { if (localLOGV) Log.v(TAG, r.id + ": restarting"); - mActivityThread.performRestartActivity(r, true /* start */); + mActivityThread.performRestartActivity(clientRecord, true /* start */); r.curState = STARTED; } if (desiredState == RESUMED) { if (localLOGV) Log.v(TAG, r.id + ": restarting and resuming"); - mActivityThread.performRestartActivity(r, true /* start */); - mActivityThread.performResumeActivity(r, true, "moveToState-CREATED"); + mActivityThread.performRestartActivity(clientRecord, true /* start */); + mActivityThread.performResumeActivity(clientRecord, true, + "moveToState-CREATED"); r.curState = RESUMED; } return; @@ -214,7 +219,8 @@ public class LocalActivityManager { if (desiredState == RESUMED) { // Need to resume it... if (localLOGV) Log.v(TAG, r.id + ": resuming"); - mActivityThread.performResumeActivity(r, true, "moveToState-STARTED"); + mActivityThread.performResumeActivity(clientRecord, true, + "moveToState-STARTED"); r.instanceState = null; r.curState = RESUMED; } @@ -352,7 +358,8 @@ public class LocalActivityManager { ArrayList<ReferrerIntent> intents = new ArrayList<>(1); intents.add(new ReferrerIntent(intent, mParent.getPackageName())); if (localLOGV) Log.v(TAG, r.id + ": new intent"); - mActivityThread.handleNewIntent(r, intents); + final ActivityClientRecord clientRecord = mActivityThread.getActivityClient(r); + mActivityThread.handleNewIntent(clientRecord, intents); r.intent = intent; moveToState(r, mCurState); if (mSingleMode) { @@ -399,7 +406,8 @@ public class LocalActivityManager { performPause(r, finish); } if (localLOGV) Log.v(TAG, r.id + ": destroying"); - mActivityThread.performDestroyActivity(r, finish, 0 /* configChanges */, + final ActivityClientRecord clientRecord = mActivityThread.getActivityClient(r); + mActivityThread.performDestroyActivity(clientRecord, finish, 0 /* configChanges */, false /* getNonConfigInstance */, "LocalActivityManager::performDestroy"); r.activity = null; r.window = null; @@ -664,7 +672,8 @@ public class LocalActivityManager { for (int i=0; i<N; i++) { LocalActivityRecord r = mActivityArray.get(i); if (localLOGV) Log.v(TAG, r.id + ": destroying"); - mActivityThread.performDestroyActivity(r, finishing, 0 /* configChanges */, + final ActivityClientRecord clientRecord = mActivityThread.getActivityClient(r); + mActivityThread.performDestroyActivity(clientRecord, finishing, 0 /* configChanges */, false /* getNonConfigInstance */, "LocalActivityManager::dispatchDestroy"); } mActivities.clear(); diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 6f3e89229e4c..6737972dc34e 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -5187,19 +5187,11 @@ public class Notification implements Parcelable bindHeaderChronometerAndTime(contentView, p); bindProfileBadge(contentView, p); bindAlertedIcon(contentView, p); - bindActivePermissions(contentView, p); bindFeedbackIcon(contentView, p); bindExpandButton(contentView, p); mN.mUsesStandardHeader = true; } - private void bindActivePermissions(RemoteViews contentView, StandardTemplateParams p) { - int color = getNeutralColor(p); - contentView.setDrawableTint(R.id.camera, false, color, PorterDuff.Mode.SRC_ATOP); - contentView.setDrawableTint(R.id.mic, false, color, PorterDuff.Mode.SRC_ATOP); - contentView.setDrawableTint(R.id.overlay, false, color, PorterDuff.Mode.SRC_ATOP); - } - private void bindFeedbackIcon(RemoteViews contentView, StandardTemplateParams p) { int color = getNeutralColor(p); contentView.setDrawableTint(R.id.feedback, false, color, PorterDuff.Mode.SRC_ATOP); diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index 8ee995d6e6be..0627bc855934 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -282,6 +282,16 @@ public class NotificationManager { = "android.app.action.INTERRUPTION_FILTER_CHANGED"; /** + * Intent that is broadcast when the state of + * {@link #hasEnabledNotificationListener(String, UserHandle)} changes. + * @hide + */ + @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static final String ACTION_NOTIFICATION_LISTENER_ENABLED_CHANGED = + "android.app.action.NOTIFICATION_LISTENER_ENABLED_CHANGED"; + + /** * Intent that is broadcast when the state of getCurrentInterruptionFilter() changes. * @hide */ diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING index fe509dea2def..4139b2faeb1b 100644 --- a/core/java/android/app/TEST_MAPPING +++ b/core/java/android/app/TEST_MAPPING @@ -65,6 +65,33 @@ { "name": "CtsInstantAppTests", "file_patterns": ["(/|^)InstantAppResolve[^/]*"] + }, + { + "name": "CtsAutoFillServiceTestCases", + "options": [ + { + "include-filter": "android.autofillservice.cts.PreSimpleSaveActivityTest" + }, + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + } + ], + "file_patterns": ["(/|^)Activity.java"] + }, + { + "name": "CtsAutoFillServiceTestCases", + "options": [ + { + "include-filter": "android.autofillservice.cts.SimpleSaveActivityTest" + }, + { + "exclude-annotation": "androidx.test.filters.FlakyTest" + }, + { + "exclude-annotation": "android.platform.test.annotations.AppModeFull" + } + ], + "file_patterns": ["(/|^)Activity.java"] } ], "postsubmit": [ diff --git a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java index 8b52242a6b6c..8a4bee98ca87 100644 --- a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java +++ b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java @@ -20,6 +20,7 @@ import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import static android.view.Display.INVALID_DISPLAY; import android.annotation.NonNull; +import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.content.res.Configuration; import android.os.IBinder; @@ -32,23 +33,24 @@ import java.util.Objects; * Activity configuration changed callback. * @hide */ -public class ActivityConfigurationChangeItem extends ClientTransactionItem { +public class ActivityConfigurationChangeItem extends ActivityTransactionItem { private Configuration mConfiguration; @Override public void preExecute(android.app.ClientTransactionHandler client, IBinder token) { + final ActivityClientRecord r = getActivityClientRecord(client, token); // Notify the client of an upcoming change in the token configuration. This ensures that // batches of config change items only process the newest configuration. - client.updatePendingActivityConfiguration(token, mConfiguration); + client.updatePendingActivityConfiguration(r, mConfiguration); } @Override - public void execute(ClientTransactionHandler client, IBinder token, + public void execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { // TODO(lifecycler): detect if PIP or multi-window mode changed and report it here. Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityConfigChanged"); - client.handleActivityConfigurationChanged(token, mConfiguration, INVALID_DISPLAY); + client.handleActivityConfigurationChanged(r, mConfiguration, INVALID_DISPLAY); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } @@ -93,7 +95,7 @@ public class ActivityConfigurationChangeItem extends ClientTransactionItem { mConfiguration = in.readTypedObject(Configuration.CREATOR); } - public static final @android.annotation.NonNull Creator<ActivityConfigurationChangeItem> CREATOR = + public static final @NonNull Creator<ActivityConfigurationChangeItem> CREATOR = new Creator<ActivityConfigurationChangeItem>() { public ActivityConfigurationChangeItem createFromParcel(Parcel in) { return new ActivityConfigurationChangeItem(in); diff --git a/core/java/android/app/servertransaction/ActivityLifecycleItem.java b/core/java/android/app/servertransaction/ActivityLifecycleItem.java index c9193a9578e7..cadb6606b1be 100644 --- a/core/java/android/app/servertransaction/ActivityLifecycleItem.java +++ b/core/java/android/app/servertransaction/ActivityLifecycleItem.java @@ -25,7 +25,7 @@ import java.lang.annotation.RetentionPolicy; * Request for lifecycle state that an activity should reach. * @hide */ -public abstract class ActivityLifecycleItem extends ClientTransactionItem { +public abstract class ActivityLifecycleItem extends ActivityTransactionItem { @IntDef(prefix = { "UNDEFINED", "PRE_", "ON_" }, value = { UNDEFINED, diff --git a/core/java/android/app/servertransaction/ActivityRelaunchItem.java b/core/java/android/app/servertransaction/ActivityRelaunchItem.java index 9844de7b6e88..87ea3f8db39c 100644 --- a/core/java/android/app/servertransaction/ActivityRelaunchItem.java +++ b/core/java/android/app/servertransaction/ActivityRelaunchItem.java @@ -18,7 +18,8 @@ package android.app.servertransaction; import static android.app.ActivityThread.DEBUG_ORDER; -import android.app.ActivityThread; +import android.annotation.NonNull; +import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.app.ResultInfo; import android.os.IBinder; @@ -36,7 +37,7 @@ import java.util.Objects; * Activity relaunch callback. * @hide */ -public class ActivityRelaunchItem extends ClientTransactionItem { +public class ActivityRelaunchItem extends ActivityTransactionItem { private static final String TAG = "ActivityRelaunchItem"; @@ -50,7 +51,7 @@ public class ActivityRelaunchItem extends ClientTransactionItem { * A record that was properly configured for relaunch. Execution will be cancelled if not * initialized after {@link #preExecute(ClientTransactionHandler, IBinder)}. */ - private ActivityThread.ActivityClientRecord mActivityClientRecord; + private ActivityClientRecord mActivityClientRecord; @Override public void preExecute(ClientTransactionHandler client, IBinder token) { @@ -59,7 +60,7 @@ public class ActivityRelaunchItem extends ClientTransactionItem { } @Override - public void execute(ClientTransactionHandler client, IBinder token, + public void execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { if (mActivityClientRecord == null) { if (DEBUG_ORDER) Slog.d(TAG, "Activity relaunch cancelled"); @@ -73,7 +74,8 @@ public class ActivityRelaunchItem extends ClientTransactionItem { @Override public void postExecute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) { - client.reportRelaunch(token, pendingActions); + final ActivityClientRecord r = getActivityClientRecord(client, token); + client.reportRelaunch(r, pendingActions); } // ObjectPoolItem implementation @@ -130,16 +132,16 @@ public class ActivityRelaunchItem extends ClientTransactionItem { mPreserveWindow = in.readBoolean(); } - public static final @android.annotation.NonNull Creator<ActivityRelaunchItem> CREATOR = + public static final @NonNull Creator<ActivityRelaunchItem> CREATOR = new Creator<ActivityRelaunchItem>() { - public ActivityRelaunchItem createFromParcel(Parcel in) { - return new ActivityRelaunchItem(in); - } - - public ActivityRelaunchItem[] newArray(int size) { - return new ActivityRelaunchItem[size]; - } - }; + public ActivityRelaunchItem createFromParcel(Parcel in) { + return new ActivityRelaunchItem(in); + } + + public ActivityRelaunchItem[] newArray(int size) { + return new ActivityRelaunchItem[size]; + } + }; @Override public boolean equals(Object o) { diff --git a/core/java/android/app/servertransaction/ActivityResultItem.java b/core/java/android/app/servertransaction/ActivityResultItem.java index 4e743caccad6..47096a8257e9 100644 --- a/core/java/android/app/servertransaction/ActivityResultItem.java +++ b/core/java/android/app/servertransaction/ActivityResultItem.java @@ -18,10 +18,11 @@ package android.app.servertransaction; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; +import android.annotation.NonNull; +import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.app.ResultInfo; import android.compat.annotation.UnsupportedAppUsage; -import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.os.Trace; @@ -33,7 +34,7 @@ import java.util.Objects; * Activity result delivery callback. * @hide */ -public class ActivityResultItem extends ClientTransactionItem { +public class ActivityResultItem extends ActivityTransactionItem { @UnsupportedAppUsage private List<ResultInfo> mResultInfoList; @@ -45,10 +46,10 @@ public class ActivityResultItem extends ClientTransactionItem { }*/ @Override - public void execute(ClientTransactionHandler client, IBinder token, + public void execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityDeliverResult"); - client.handleSendResult(token, mResultInfoList, "ACTIVITY_RESULT"); + client.handleSendResult(r, mResultInfoList, "ACTIVITY_RESULT"); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } @@ -88,7 +89,7 @@ public class ActivityResultItem extends ClientTransactionItem { mResultInfoList = in.createTypedArrayList(ResultInfo.CREATOR); } - public static final @android.annotation.NonNull Parcelable.Creator<ActivityResultItem> CREATOR = + public static final @NonNull Parcelable.Creator<ActivityResultItem> CREATOR = new Parcelable.Creator<ActivityResultItem>() { public ActivityResultItem createFromParcel(Parcel in) { return new ActivityResultItem(in); diff --git a/core/java/android/app/servertransaction/ActivityTransactionItem.java b/core/java/android/app/servertransaction/ActivityTransactionItem.java new file mode 100644 index 000000000000..f7d7e9d20ab9 --- /dev/null +++ b/core/java/android/app/servertransaction/ActivityTransactionItem.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2020 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.app.servertransaction; + +import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; + +import android.annotation.NonNull; +import android.app.ActivityThread.ActivityClientRecord; +import android.app.ClientTransactionHandler; +import android.os.IBinder; + +import com.android.internal.annotations.VisibleForTesting; + +/** + * An activity-targeting callback message to a client that can be scheduled and executed. + * It also provides nullity-free version of + * {@link #execute(ClientTransactionHandler, IBinder, PendingTransactionActions)} for child class + * to inherit. + * + * @see ClientTransaction + * @see ClientTransactionItem + * @see com.android.server.wm.ClientLifecycleManager + * @hide + */ +public abstract class ActivityTransactionItem extends ClientTransactionItem { + @Override + public final void execute(ClientTransactionHandler client, IBinder token, + PendingTransactionActions pendingActions) { + final ActivityClientRecord r = getActivityClientRecord(client, token); + + execute(client, r, pendingActions); + } + + /** + * Like {@link #execute(ClientTransactionHandler, IBinder, PendingTransactionActions)}, + * but take non-null {@link ActivityClientRecord} as a parameter. + */ + @VisibleForTesting(visibility = PACKAGE) + public abstract void execute(@NonNull ClientTransactionHandler client, + @NonNull ActivityClientRecord r, PendingTransactionActions pendingActions); + + @NonNull ActivityClientRecord getActivityClientRecord( + @NonNull ClientTransactionHandler client, IBinder token) { + final ActivityClientRecord r = client.getActivityClient(token); + if (r == null) { + throw new IllegalArgumentException("Activity client record must not be null to execute " + + "transaction item"); + } + if (client.getActivity(token) == null) { + throw new IllegalArgumentException("Activity must not be null to execute " + + "transaction item"); + } + return r; + } +} diff --git a/core/java/android/app/servertransaction/DestroyActivityItem.java b/core/java/android/app/servertransaction/DestroyActivityItem.java index 3ee761477efd..1611369497e9 100644 --- a/core/java/android/app/servertransaction/DestroyActivityItem.java +++ b/core/java/android/app/servertransaction/DestroyActivityItem.java @@ -18,6 +18,8 @@ package android.app.servertransaction; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; +import android.annotation.NonNull; +import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.os.IBinder; import android.os.Parcel; @@ -38,10 +40,10 @@ public class DestroyActivityItem extends ActivityLifecycleItem { } @Override - public void execute(ClientTransactionHandler client, IBinder token, + public void execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityDestroy"); - client.handleDestroyActivity(token, mFinished, mConfigChanges, + client.handleDestroyActivity(r, mFinished, mConfigChanges, false /* getNonConfigInstance */, "DestroyActivityItem"); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } @@ -92,7 +94,7 @@ public class DestroyActivityItem extends ActivityLifecycleItem { mConfigChanges = in.readInt(); } - public static final @android.annotation.NonNull Creator<DestroyActivityItem> CREATOR = + public static final @NonNull Creator<DestroyActivityItem> CREATOR = new Creator<DestroyActivityItem>() { public DestroyActivityItem createFromParcel(Parcel in) { return new DestroyActivityItem(in); diff --git a/core/java/android/app/servertransaction/EnterPipRequestedItem.java b/core/java/android/app/servertransaction/EnterPipRequestedItem.java index b2a1276fa178..b7e81a56afad 100644 --- a/core/java/android/app/servertransaction/EnterPipRequestedItem.java +++ b/core/java/android/app/servertransaction/EnterPipRequestedItem.java @@ -16,20 +16,20 @@ package android.app.servertransaction; +import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; -import android.os.IBinder; import android.os.Parcel; /** * Request an activity to enter picture-in-picture mode. * @hide */ -public final class EnterPipRequestedItem extends ClientTransactionItem { +public final class EnterPipRequestedItem extends ActivityTransactionItem { @Override - public void execute(ClientTransactionHandler client, IBinder token, + public void execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { - client.handlePictureInPictureRequested(token); + client.handlePictureInPictureRequested(r); } // ObjectPoolItem implementation diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java index 2e7b6262c785..77457af77340 100644 --- a/core/java/android/app/servertransaction/LaunchActivityItem.java +++ b/core/java/android/app/servertransaction/LaunchActivityItem.java @@ -18,6 +18,7 @@ package android.app.servertransaction; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; +import android.annotation.NonNull; import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.app.ProfilerInfo; @@ -163,7 +164,7 @@ public class LaunchActivityItem extends ClientTransactionItem { in.readTypedObject(FixedRotationAdjustments.CREATOR)); } - public static final @android.annotation.NonNull Creator<LaunchActivityItem> CREATOR = + public static final @NonNull Creator<LaunchActivityItem> CREATOR = new Creator<LaunchActivityItem>() { public LaunchActivityItem createFromParcel(Parcel in) { return new LaunchActivityItem(in); diff --git a/core/java/android/app/servertransaction/MoveToDisplayItem.java b/core/java/android/app/servertransaction/MoveToDisplayItem.java index 9a457a3aad40..32de53f189b0 100644 --- a/core/java/android/app/servertransaction/MoveToDisplayItem.java +++ b/core/java/android/app/servertransaction/MoveToDisplayItem.java @@ -19,6 +19,7 @@ package android.app.servertransaction; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import android.annotation.NonNull; +import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.content.res.Configuration; import android.os.IBinder; @@ -31,23 +32,24 @@ import java.util.Objects; * Activity move to a different display message. * @hide */ -public class MoveToDisplayItem extends ClientTransactionItem { +public class MoveToDisplayItem extends ActivityTransactionItem { private int mTargetDisplayId; private Configuration mConfiguration; @Override public void preExecute(ClientTransactionHandler client, IBinder token) { + final ActivityClientRecord r = getActivityClientRecord(client, token); // Notify the client of an upcoming change in the token configuration. This ensures that // batches of config change items only process the newest configuration. - client.updatePendingActivityConfiguration(token, mConfiguration); + client.updatePendingActivityConfiguration(r, mConfiguration); } @Override - public void execute(ClientTransactionHandler client, IBinder token, + public void execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityMovedToDisplay"); - client.handleActivityConfigurationChanged(token, mConfiguration, mTargetDisplayId); + client.handleActivityConfigurationChanged(r, mConfiguration, mTargetDisplayId); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } @@ -96,7 +98,8 @@ public class MoveToDisplayItem extends ClientTransactionItem { mConfiguration = in.readTypedObject(Configuration.CREATOR); } - public static final @android.annotation.NonNull Creator<MoveToDisplayItem> CREATOR = new Creator<MoveToDisplayItem>() { + public static final @NonNull Creator<MoveToDisplayItem> CREATOR = + new Creator<MoveToDisplayItem>() { public MoveToDisplayItem createFromParcel(Parcel in) { return new MoveToDisplayItem(in); } diff --git a/core/java/android/app/servertransaction/NewIntentItem.java b/core/java/android/app/servertransaction/NewIntentItem.java index 6a4996da38ca..b4e2a7bfa10f 100644 --- a/core/java/android/app/servertransaction/NewIntentItem.java +++ b/core/java/android/app/servertransaction/NewIntentItem.java @@ -19,9 +19,10 @@ package android.app.servertransaction; import static android.app.servertransaction.ActivityLifecycleItem.ON_RESUME; import static android.app.servertransaction.ActivityLifecycleItem.UNDEFINED; +import android.annotation.NonNull; +import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.compat.annotation.UnsupportedAppUsage; -import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.os.Trace; @@ -35,7 +36,7 @@ import java.util.Objects; * New intent message. * @hide */ -public class NewIntentItem extends ClientTransactionItem { +public class NewIntentItem extends ActivityTransactionItem { @UnsupportedAppUsage private List<ReferrerIntent> mIntents; @@ -47,10 +48,10 @@ public class NewIntentItem extends ClientTransactionItem { } @Override - public void execute(ClientTransactionHandler client, IBinder token, + public void execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityNewIntent"); - client.handleNewIntent(token, mIntents); + client.handleNewIntent(r, mIntents); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } @@ -94,7 +95,7 @@ public class NewIntentItem extends ClientTransactionItem { mIntents = in.createTypedArrayList(ReferrerIntent.CREATOR); } - public static final @android.annotation.NonNull Parcelable.Creator<NewIntentItem> CREATOR = + public static final @NonNull Parcelable.Creator<NewIntentItem> CREATOR = new Parcelable.Creator<NewIntentItem>() { public NewIntentItem createFromParcel(Parcel in) { return new NewIntentItem(in); diff --git a/core/java/android/app/servertransaction/PauseActivityItem.java b/core/java/android/app/servertransaction/PauseActivityItem.java index f65c843ee76f..cb154e9585e6 100644 --- a/core/java/android/app/servertransaction/PauseActivityItem.java +++ b/core/java/android/app/servertransaction/PauseActivityItem.java @@ -18,8 +18,9 @@ package android.app.servertransaction; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; -import android.app.ActivityManager; +import android.annotation.NonNull; import android.app.ActivityTaskManager; +import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.os.IBinder; import android.os.Parcel; @@ -40,10 +41,10 @@ public class PauseActivityItem extends ActivityLifecycleItem { private boolean mDontReport; @Override - public void execute(ClientTransactionHandler client, IBinder token, + public void execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityPause"); - client.handlePauseActivity(token, mFinished, mUserLeaving, mConfigChanges, pendingActions, + client.handlePauseActivity(r, mFinished, mUserLeaving, mConfigChanges, pendingActions, "PAUSE_ACTIVITY_ITEM"); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } @@ -130,7 +131,7 @@ public class PauseActivityItem extends ActivityLifecycleItem { mDontReport = in.readBoolean(); } - public static final @android.annotation.NonNull Creator<PauseActivityItem> CREATOR = + public static final @NonNull Creator<PauseActivityItem> CREATOR = new Creator<PauseActivityItem>() { public PauseActivityItem createFromParcel(Parcel in) { return new PauseActivityItem(in); diff --git a/core/java/android/app/servertransaction/ResumeActivityItem.java b/core/java/android/app/servertransaction/ResumeActivityItem.java index 905076b08e69..d2a156c37c90 100644 --- a/core/java/android/app/servertransaction/ResumeActivityItem.java +++ b/core/java/android/app/servertransaction/ResumeActivityItem.java @@ -18,8 +18,10 @@ package android.app.servertransaction; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; +import android.annotation.NonNull; import android.app.ActivityManager; import android.app.ActivityTaskManager; +import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.os.IBinder; import android.os.Parcel; @@ -46,10 +48,10 @@ public class ResumeActivityItem extends ActivityLifecycleItem { } @Override - public void execute(ClientTransactionHandler client, IBinder token, + public void execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume"); - client.handleResumeActivity(token, true /* finalStateRequest */, mIsForward, + client.handleResumeActivity(r, true /* finalStateRequest */, mIsForward, "RESUME_ACTIVITY"); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } @@ -128,7 +130,7 @@ public class ResumeActivityItem extends ActivityLifecycleItem { mIsForward = in.readBoolean(); } - public static final @android.annotation.NonNull Creator<ResumeActivityItem> CREATOR = + public static final @NonNull Creator<ResumeActivityItem> CREATOR = new Creator<ResumeActivityItem>() { public ResumeActivityItem createFromParcel(Parcel in) { return new ResumeActivityItem(in); diff --git a/core/java/android/app/servertransaction/StartActivityItem.java b/core/java/android/app/servertransaction/StartActivityItem.java index 4fbe02b9cf76..ae0bd24218fb 100644 --- a/core/java/android/app/servertransaction/StartActivityItem.java +++ b/core/java/android/app/servertransaction/StartActivityItem.java @@ -18,8 +18,9 @@ package android.app.servertransaction; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; +import android.annotation.NonNull; +import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; -import android.os.IBinder; import android.os.Parcel; import android.os.Trace; @@ -32,10 +33,10 @@ public class StartActivityItem extends ActivityLifecycleItem { private static final String TAG = "StartActivityItem"; @Override - public void execute(ClientTransactionHandler client, IBinder token, + public void execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "startActivityItem"); - client.handleStartActivity(token, pendingActions); + client.handleStartActivity(r, pendingActions); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } @@ -79,7 +80,7 @@ public class StartActivityItem extends ActivityLifecycleItem { // Empty } - public static final @android.annotation.NonNull Creator<StartActivityItem> CREATOR = + public static final @NonNull Creator<StartActivityItem> CREATOR = new Creator<StartActivityItem>() { public StartActivityItem createFromParcel(Parcel in) { return new StartActivityItem(in); diff --git a/core/java/android/app/servertransaction/StopActivityItem.java b/core/java/android/app/servertransaction/StopActivityItem.java index 8668bd49c8f5..7708104da16a 100644 --- a/core/java/android/app/servertransaction/StopActivityItem.java +++ b/core/java/android/app/servertransaction/StopActivityItem.java @@ -18,6 +18,8 @@ package android.app.servertransaction; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; +import android.annotation.NonNull; +import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.os.IBinder; import android.os.Parcel; @@ -34,10 +36,10 @@ public class StopActivityItem extends ActivityLifecycleItem { private int mConfigChanges; @Override - public void execute(ClientTransactionHandler client, IBinder token, + public void execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStop"); - client.handleStopActivity(token, mConfigChanges, pendingActions, + client.handleStopActivity(r, mConfigChanges, pendingActions, true /* finalStateRequest */, "STOP_ACTIVITY_ITEM"); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } @@ -93,7 +95,7 @@ public class StopActivityItem extends ActivityLifecycleItem { mConfigChanges = in.readInt(); } - public static final @android.annotation.NonNull Creator<StopActivityItem> CREATOR = + public static final @NonNull Creator<StopActivityItem> CREATOR = new Creator<StopActivityItem>() { public StopActivityItem createFromParcel(Parcel in) { return new StopActivityItem(in); diff --git a/core/java/android/app/servertransaction/TopResumedActivityChangeItem.java b/core/java/android/app/servertransaction/TopResumedActivityChangeItem.java index c7e4c3641631..345c1dd336ab 100644 --- a/core/java/android/app/servertransaction/TopResumedActivityChangeItem.java +++ b/core/java/android/app/servertransaction/TopResumedActivityChangeItem.java @@ -17,7 +17,9 @@ package android.app.servertransaction; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; +import android.annotation.NonNull; import android.app.ActivityTaskManager; +import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.os.IBinder; import android.os.Parcel; @@ -28,15 +30,15 @@ import android.os.Trace; * Top resumed activity changed callback. * @hide */ -public class TopResumedActivityChangeItem extends ClientTransactionItem { +public class TopResumedActivityChangeItem extends ActivityTransactionItem { private boolean mOnTop; @Override - public void execute(ClientTransactionHandler client, IBinder token, + public void execute(ClientTransactionHandler client, ActivityClientRecord r, PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "topResumedActivityChangeItem"); - client.handleTopResumedActivityChanged(token, mOnTop, "topResumedActivityChangeItem"); + client.handleTopResumedActivityChanged(r, mOnTop, "topResumedActivityChangeItem"); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } @@ -97,16 +99,16 @@ public class TopResumedActivityChangeItem extends ClientTransactionItem { mOnTop = in.readBoolean(); } - public static final @android.annotation.NonNull Creator<TopResumedActivityChangeItem> CREATOR = + public static final @NonNull Creator<TopResumedActivityChangeItem> CREATOR = new Creator<TopResumedActivityChangeItem>() { - public TopResumedActivityChangeItem createFromParcel(Parcel in) { - return new TopResumedActivityChangeItem(in); - } - - public TopResumedActivityChangeItem[] newArray(int size) { - return new TopResumedActivityChangeItem[size]; - } - }; + public TopResumedActivityChangeItem createFromParcel(Parcel in) { + return new TopResumedActivityChangeItem(in); + } + + public TopResumedActivityChangeItem[] newArray(int size) { + return new TopResumedActivityChangeItem[size]; + } + }; @Override public boolean equals(Object o) { diff --git a/core/java/android/app/servertransaction/TransactionExecutor.java b/core/java/android/app/servertransaction/TransactionExecutor.java index 17fcda587322..3dcf2cb5f13e 100644 --- a/core/java/android/app/servertransaction/TransactionExecutor.java +++ b/core/java/android/app/servertransaction/TransactionExecutor.java @@ -218,29 +218,29 @@ public class TransactionExecutor { null /* customIntent */); break; case ON_START: - mTransactionHandler.handleStartActivity(r.token, mPendingActions); + mTransactionHandler.handleStartActivity(r, mPendingActions); break; case ON_RESUME: - mTransactionHandler.handleResumeActivity(r.token, false /* finalStateRequest */, + mTransactionHandler.handleResumeActivity(r, false /* finalStateRequest */, r.isForward, "LIFECYCLER_RESUME_ACTIVITY"); break; case ON_PAUSE: - mTransactionHandler.handlePauseActivity(r.token, false /* finished */, + mTransactionHandler.handlePauseActivity(r, false /* finished */, false /* userLeaving */, 0 /* configChanges */, mPendingActions, "LIFECYCLER_PAUSE_ACTIVITY"); break; case ON_STOP: - mTransactionHandler.handleStopActivity(r.token, 0 /* configChanges */, + mTransactionHandler.handleStopActivity(r, 0 /* configChanges */, mPendingActions, false /* finalStateRequest */, "LIFECYCLER_STOP_ACTIVITY"); break; case ON_DESTROY: - mTransactionHandler.handleDestroyActivity(r.token, false /* finishing */, + mTransactionHandler.handleDestroyActivity(r, false /* finishing */, 0 /* configChanges */, false /* getNonConfigInstance */, "performLifecycleSequence. cycling to:" + path.get(size - 1)); break; case ON_RESTART: - mTransactionHandler.performRestartActivity(r.token, false /* start */); + mTransactionHandler.performRestartActivity(r, false /* start */); break; default: throw new IllegalArgumentException("Unexpected lifecycle state: " + state); diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java index bd1eea51f8af..cef6ab094177 100644 --- a/core/java/android/app/slice/SliceProvider.java +++ b/core/java/android/app/slice/SliceProvider.java @@ -155,10 +155,6 @@ public abstract class SliceProvider extends ContentProvider { /** * @hide */ - public static final String EXTRA_PROVIDER_PKG = "provider_pkg"; - /** - * @hide - */ public static final String EXTRA_RESULT = "result"; private static final boolean DEBUG = false; @@ -519,7 +515,6 @@ public abstract class SliceProvider extends ContentProvider { com.android.internal.R.string.config_slicePermissionComponent))); intent.putExtra(EXTRA_BIND_URI, sliceUri); intent.putExtra(EXTRA_PKG, callingPackage); - intent.putExtra(EXTRA_PROVIDER_PKG, context.getPackageName()); // Unique pending intent. intent.setData(sliceUri.buildUpon().appendQueryParameter("package", callingPackage) .build()); diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java index 19cb13c7e114..4f949cfc62a5 100644 --- a/core/java/android/hardware/face/FaceManager.java +++ b/core/java/android/hardware/face/FaceManager.java @@ -72,6 +72,8 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan private static final int MSG_SET_FEATURE_COMPLETED = 107; private static final int MSG_CHALLENGE_GENERATED = 108; private static final int MSG_FACE_DETECTED = 109; + private static final int MSG_CHALLENGE_INTERRUPTED = 110; + private static final int MSG_CHALLENGE_INTERRUPT_FINISHED = 111; private final IFaceService mService; private final Context mContext; @@ -150,6 +152,16 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan mHandler.obtainMessage(MSG_CHALLENGE_GENERATED, challenge).sendToTarget(); } } + + @Override + public void onChallengeInterrupted(int sensorId) { + mHandler.obtainMessage(MSG_CHALLENGE_INTERRUPTED, sensorId).sendToTarget(); + } + + @Override + public void onChallengeInterruptFinished(int sensorId) { + mHandler.obtainMessage(MSG_CHALLENGE_INTERRUPT_FINISHED, sensorId).sendToTarget(); + } }; /** @@ -1071,10 +1083,25 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan } /** + * Callback structure provided to {@link #generateChallenge(GenerateChallengeCallback)}. * @hide */ public interface GenerateChallengeCallback { + /** + * Invoked when a challenge has been generated. + */ void onGenerateChallengeResult(long challenge); + + /** + * Invoked if the challenge has not been revoked and a subsequent caller/owner invokes + * {@link #generateChallenge(GenerateChallengeCallback)}, but + */ + default void onChallengeInterrupted(int sensorId) {} + + /** + * Invoked when the interrupting client has finished (e.g. revoked its challenge). + */ + default void onChallengeInterruptFinished(int sensorId) {} } private abstract static class InternalGenerateChallengeCallback @@ -1157,6 +1184,12 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan sendFaceDetected(msg.arg1 /* sensorId */, msg.arg2 /* userId */, (boolean) msg.obj /* isStrongBiometric */); break; + case MSG_CHALLENGE_INTERRUPTED: + sendChallengeInterrupted((int) msg.obj /* sensorId */); + break; + case MSG_CHALLENGE_INTERRUPT_FINISHED: + sendChallengeInterruptFinished((int) msg.obj /* sensorId */); + break; default: Slog.w(TAG, "Unknown message: " + msg.what); } @@ -1193,6 +1226,22 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan mFaceDetectionCallback.onFaceDetected(sensorId, userId, isStrongBiometric); } + private void sendChallengeInterrupted(int sensorId) { + if (mGenerateChallengeCallback == null) { + Slog.e(TAG, "sendChallengeInterrupted, callback null"); + return; + } + mGenerateChallengeCallback.onChallengeInterrupted(sensorId); + } + + private void sendChallengeInterruptFinished(int sensorId) { + if (mGenerateChallengeCallback == null) { + Slog.e(TAG, "sendChallengeInterruptFinished, callback null"); + return; + } + mGenerateChallengeCallback.onChallengeInterruptFinished(sensorId); + } + private void sendRemovedResult(Face face, int remaining) { if (mRemovalCallback == null) { return; diff --git a/core/java/android/hardware/face/IFaceServiceReceiver.aidl b/core/java/android/hardware/face/IFaceServiceReceiver.aidl index 2600b7def03a..108f4f69bdd8 100644 --- a/core/java/android/hardware/face/IFaceServiceReceiver.aidl +++ b/core/java/android/hardware/face/IFaceServiceReceiver.aidl @@ -32,4 +32,6 @@ oneway interface IFaceServiceReceiver { void onFeatureSet(boolean success, int feature); void onFeatureGet(boolean success, int feature, boolean value); void onChallengeGenerated(long challenge); + void onChallengeInterrupted(int sensorId); + void onChallengeInterruptFinished(int sensorId); } diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 7234eb1d81cd..cd26079a7bac 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -503,6 +503,10 @@ public class NetworkTemplate implements Parcelable { for (final int ratType : ratTypes) { collapsedRatTypes.add(NetworkTemplate.getCollapsedRatType(ratType)); } + // Add NETWORK_TYPE_5G_NSA to the returned list since 5G NSA is a virtual RAT type and + // it is not in TelephonyManager#NETWORK_TYPE_* constants. + // See {@link NetworkTemplate#NETWORK_TYPE_5G_NSA}. + collapsedRatTypes.add(NetworkTemplate.getCollapsedRatType(NETWORK_TYPE_5G_NSA)); // Ensure that unknown type is returned. collapsedRatTypes.add(TelephonyManager.NETWORK_TYPE_UNKNOWN); return toIntArray(collapsedRatTypes); diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 1050c7f8b4f4..8e865e7ab313 100755 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -1012,10 +1012,16 @@ public class Build { /** * Q. - * <p> - * <em>Why? Why, to give you a taste of your future, a preview of things - * to come. Con permiso, Capitan. The hall is rented, the orchestra - * engaged. It's now time to see if you can dance.</em> + * + * <p>Applications targeting this or a later release will get these new changes in behavior. + * For more information about this release, see the + * <a href="/about/versions/10">Android 10 overview</a>.</p> + * <ul> + * <li><a href="/about/versions/10/behavior-changes-all">Behavior changes: all apps</a></li> + * <li><a href="/about/versions/10/behavior-changes-10">Behavior changes: apps targeting API + * 29+</a></li> + * </ul> + * */ public static final int Q = 29; diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java index 8ad35e7eb37d..e2e61406ba95 100644 --- a/core/java/android/permission/PermissionControllerService.java +++ b/core/java/android/permission/PermissionControllerService.java @@ -35,6 +35,8 @@ import android.annotation.NonNull; import android.annotation.SystemApi; import android.app.Service; import android.app.admin.DevicePolicyManager.PermissionGrantState; +import android.compat.annotation.ChangeId; +import android.compat.annotation.Disabled; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; @@ -83,6 +85,15 @@ public abstract class PermissionControllerService extends Service { public static final String SERVICE_INTERFACE = "android.permission.PermissionControllerService"; /** + * A ChangeId indicating that this device supports camera and mic indicators. Will be "false" + * if present, because the CompatChanges#isChangeEnabled method returns true if the change id + * is not present. + */ + @ChangeId + @Disabled + private static final long CAMERA_MIC_INDICATORS_NOT_PRESENT = 162547999L; + + /** * Revoke a set of runtime permissions for various apps. * * @param requests The permissions to revoke as {@code Map<packageName, List<permission>>} diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java index 0c190719af57..b9d27e923615 100644 --- a/core/java/android/permission/PermissionManager.java +++ b/core/java/android/permission/PermissionManager.java @@ -25,6 +25,7 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; +import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.ActivityThread; import android.app.IActivityManager; @@ -637,24 +638,25 @@ public final class PermissionManager { private static final class PackageNamePermissionQuery { final String permName; final String pkgName; - final int uid; + final int userId; - PackageNamePermissionQuery(@Nullable String permName, @Nullable String pkgName, int uid) { + PackageNamePermissionQuery(@Nullable String permName, @Nullable String pkgName, + @UserIdInt int userId) { this.permName = permName; this.pkgName = pkgName; - this.uid = uid; + this.userId = userId; } @Override public String toString() { return String.format( - "PackageNamePermissionQuery(pkgName=\"%s\", permName=\"%s, uid=%s\")", - pkgName, permName, uid); + "PackageNamePermissionQuery(pkgName=\"%s\", permName=\"%s, userId=%s\")", + pkgName, permName, userId); } @Override public int hashCode() { - return Objects.hash(permName, pkgName, uid); + return Objects.hash(permName, pkgName, userId); } @Override @@ -670,16 +672,16 @@ public final class PermissionManager { } return Objects.equals(permName, other.permName) && Objects.equals(pkgName, other.pkgName) - && uid == other.uid; + && userId == other.userId; } } /* @hide */ private static int checkPackageNamePermissionUncached( - String permName, String pkgName, int uid) { + String permName, String pkgName, @UserIdInt int userId) { try { return ActivityThread.getPermissionManager().checkPermission( - permName, pkgName, uid); + permName, pkgName, userId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -693,7 +695,7 @@ public final class PermissionManager { @Override protected Integer recompute(PackageNamePermissionQuery query) { return checkPackageNamePermissionUncached( - query.permName, query.pkgName, query.uid); + query.permName, query.pkgName, query.userId); } }; @@ -702,9 +704,10 @@ public final class PermissionManager { * * @hide */ - public static int checkPackageNamePermission(String permName, String pkgName, int uid) { + public static int checkPackageNamePermission(String permName, String pkgName, + @UserIdInt int userId) { return sPackageNamePermissionCache.query( - new PackageNamePermissionQuery(permName, pkgName, uid)); + new PackageNamePermissionQuery(permName, pkgName, userId)); } /** diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 660455e59a4a..7ad0e7d337d2 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -8974,6 +8974,14 @@ public final class Settings { public static final String MEDIA_CONTROLS_RESUME = "qs_media_resumption"; /** + * Controls which packages are blocked from persisting in media controls when resumption is + * enabled. The list of packages is set by the user in the Settings app. + * @see Settings.Secure#MEDIA_CONTROLS_RESUME + * @hide + */ + public static final String MEDIA_CONTROLS_RESUME_BLOCKED = "qs_media_resumption_blocked"; + + /** * Controls if window magnification is enabled. * @hide */ diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java index c1998c6009cf..82f60366a814 100644 --- a/core/java/android/view/ImeInsetsSourceConsumer.java +++ b/core/java/android/view/ImeInsetsSourceConsumer.java @@ -69,7 +69,7 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { } public void onServedEditorChanged(EditorInfo info) { - if (isDummyOrEmptyEditor(info)) { + if (isFallbackOrEmptyEditor(info)) { mShowOnNextImeRender = false; } mFocusedEditor = info; @@ -167,15 +167,15 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { } } - private boolean isDummyOrEmptyEditor(EditorInfo info) { - // TODO(b/123044812): Handle dummy input gracefully in IME Insets API + private boolean isFallbackOrEmptyEditor(EditorInfo info) { + // TODO(b/123044812): Handle fallback input gracefully in IME Insets API return info == null || (info.fieldId <= 0 && info.inputType <= 0); } private boolean isServedEditorRendered() { if (mFocusedEditor == null || mPreRenderedEditor == null - || isDummyOrEmptyEditor(mFocusedEditor) - || isDummyOrEmptyEditor(mPreRenderedEditor)) { + || isFallbackOrEmptyEditor(mFocusedEditor) + || isFallbackOrEmptyEditor(mPreRenderedEditor)) { // No view is focused or ready. return false; } diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java index bf94670e1ca3..6136a80978b7 100644 --- a/core/java/android/view/NotificationHeaderView.java +++ b/core/java/android/view/NotificationHeaderView.java @@ -52,14 +52,12 @@ public class NotificationHeaderView extends ViewGroup { private View mHeaderText; private View mSecondaryHeaderText; private OnClickListener mExpandClickListener; - private OnClickListener mAppOpsListener; private OnClickListener mFeedbackListener; private HeaderTouchListener mTouchListener = new HeaderTouchListener(); private LinearLayout mTransferChip; private NotificationExpandButton mExpandButton; private CachingIconView mIcon; private View mProfileBadge; - private View mAppOps; private View mFeedbackIcon; private boolean mExpanded; private boolean mShowExpandButtonAtEnd; @@ -117,7 +115,6 @@ public class NotificationHeaderView extends ViewGroup { mExpandButton = findViewById(com.android.internal.R.id.expand_button); mIcon = findViewById(com.android.internal.R.id.icon); mProfileBadge = findViewById(com.android.internal.R.id.profile_badge); - mAppOps = findViewById(com.android.internal.R.id.app_ops); mFeedbackIcon = findViewById(com.android.internal.R.id.feedback); } @@ -146,7 +143,6 @@ public class NotificationHeaderView extends ViewGroup { // Icons that should go at the end if ((child == mExpandButton && mShowExpandButtonAtEnd) || child == mProfileBadge - || child == mAppOps || child == mFeedbackIcon || child == mTransferChip) { iconWidth += lp.leftMargin + lp.rightMargin + child.getMeasuredWidth(); @@ -212,7 +208,6 @@ public class NotificationHeaderView extends ViewGroup { // Icons that should go at the end if ((child == mExpandButton && mShowExpandButtonAtEnd) || child == mProfileBadge - || child == mAppOps || child == mFeedbackIcon || child == mTransferChip) { if (end == getMeasuredWidth()) { @@ -282,7 +277,7 @@ public class NotificationHeaderView extends ViewGroup { } private void updateTouchListener() { - if (mExpandClickListener == null && mAppOpsListener == null && mFeedbackListener == null) { + if (mExpandClickListener == null && mFeedbackListener == null) { setOnTouchListener(null); return; } @@ -291,14 +286,6 @@ public class NotificationHeaderView extends ViewGroup { } /** - * Sets onclick listener for app ops icons. - */ - public void setAppOpsOnClickListener(OnClickListener l) { - mAppOpsListener = l; - updateTouchListener(); - } - - /** * Sets onclick listener for feedback icon. */ public void setFeedbackOnClickListener(OnClickListener l) { @@ -394,7 +381,6 @@ public class NotificationHeaderView extends ViewGroup { private final ArrayList<Rect> mTouchRects = new ArrayList<>(); private Rect mExpandButtonRect; - private Rect mAppOpsRect; private Rect mFeedbackRect; private int mTouchSlop; private boolean mTrackGesture; @@ -408,9 +394,7 @@ public class NotificationHeaderView extends ViewGroup { mTouchRects.clear(); addRectAroundView(mIcon); mExpandButtonRect = addRectAroundView(mExpandButton); - mAppOpsRect = addRectAroundView(mAppOps); mFeedbackRect = addRectAroundView(mFeedbackIcon); - setTouchDelegate(new TouchDelegate(mAppOpsRect, mAppOps)); addWidthRect(); mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); } @@ -471,11 +455,7 @@ public class NotificationHeaderView extends ViewGroup { break; case MotionEvent.ACTION_UP: if (mTrackGesture) { - if (mAppOps.isVisibleToUser() && (mAppOpsRect.contains((int) x, (int) y) - || mAppOpsRect.contains((int) mDownX, (int) mDownY))) { - mAppOps.performClick(); - return true; - } else if (mFeedbackIcon.isVisibleToUser() + if (mFeedbackIcon.isVisibleToUser() && (mFeedbackRect.contains((int) x, (int) y)) || mFeedbackRect.contains((int) mDownX, (int) mDownY)) { mFeedbackIcon.performClick(); diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java index d5d631ac1dc7..eef27262c699 100644 --- a/core/java/android/view/inputmethod/BaseInputConnection.java +++ b/core/java/android/view/inputmethod/BaseInputConnection.java @@ -54,7 +54,7 @@ public class BaseInputConnection implements InputConnection { /** @hide */ protected final InputMethodManager mIMM; final View mTargetView; - final boolean mDummyMode; + final boolean mFallbackMode; private Object[] mDefaultComposingSpans; @@ -64,14 +64,14 @@ public class BaseInputConnection implements InputConnection { BaseInputConnection(InputMethodManager mgr, boolean fullEditor) { mIMM = mgr; mTargetView = null; - mDummyMode = !fullEditor; + mFallbackMode = !fullEditor; } public BaseInputConnection(View targetView, boolean fullEditor) { mIMM = (InputMethodManager)targetView.getContext().getSystemService( Context.INPUT_METHOD_SERVICE); mTargetView = targetView; - mDummyMode = !fullEditor; + mFallbackMode = !fullEditor; } public static final void removeComposingSpans(Spannable text) { @@ -189,7 +189,7 @@ public class BaseInputConnection implements InputConnection { /** * Default implementation replaces any existing composing text with - * the given text. In addition, only if dummy mode, a key event is + * the given text. In addition, only if fallback mode, a key event is * sent for the new text and the current editable buffer cleared. */ public boolean commitText(CharSequence text, int newCursorPosition) { @@ -445,7 +445,7 @@ public class BaseInputConnection implements InputConnection { /** * The default implementation removes the composing state from the - * current editable text. In addition, only if dummy mode, a key event is + * current editable text. In addition, only if fallback mode, a key event is * sent for the new text and the current editable buffer cleared. */ public boolean finishComposingText() { @@ -454,7 +454,7 @@ public class BaseInputConnection implements InputConnection { if (content != null) { beginBatchEdit(); removeComposingSpans(content); - // Note: sendCurrentText does nothing unless mDummyMode is set + // Note: sendCurrentText does nothing unless mFallbackMode is set sendCurrentText(); endBatchEdit(); } @@ -464,10 +464,10 @@ public class BaseInputConnection implements InputConnection { /** * The default implementation uses TextUtils.getCapsMode to get the * cursor caps mode for the current selection position in the editable - * text, unless in dummy mode in which case 0 is always returned. + * text, unless in fallback mode in which case 0 is always returned. */ public int getCursorCapsMode(int reqModes) { - if (mDummyMode) return 0; + if (mFallbackMode) return 0; final Editable content = getEditable(); if (content == null) return 0; @@ -664,7 +664,7 @@ public class BaseInputConnection implements InputConnection { content.setSpan(COMPOSING, a, b, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_COMPOSING); - // Note: sendCurrentText does nothing unless mDummyMode is set + // Note: sendCurrentText does nothing unless mFallbackMode is set sendCurrentText(); endBatchEdit(); } @@ -715,7 +715,7 @@ public class BaseInputConnection implements InputConnection { } private void sendCurrentText() { - if (!mDummyMode) { + if (!mFallbackMode) { return; } diff --git a/core/java/android/webkit/UserPackage.java b/core/java/android/webkit/UserPackage.java index 556b24c94b36..2e5ee041e54c 100644 --- a/core/java/android/webkit/UserPackage.java +++ b/core/java/android/webkit/UserPackage.java @@ -99,7 +99,7 @@ public class UserPackage { private static List<UserInfo> getAllUsers(Context context) { UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE); - return userManager.getUsers(false); + return userManager.getUsers(); } } diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java index 330c15cc4614..c82a6564c1d7 100644 --- a/core/java/com/android/internal/util/Preconditions.java +++ b/core/java/com/android/internal/util/Preconditions.java @@ -187,6 +187,32 @@ public class Preconditions { } /** + * Ensures the truth of an expression involving whether the calling identity is authorized to + * call the calling method. + * + * @param expression a boolean expression + * @throws SecurityException if {@code expression} is false + */ + public static void checkCallAuthorization(final boolean expression) { + if (!expression) { + throw new SecurityException("Calling identity is not authorized"); + } + } + + /** + * Ensures the truth of an expression involving whether the calling user is authorized to + * call the calling method. + * + * @param expression a boolean expression + * @throws SecurityException if {@code expression} is false + */ + public static void checkCallingUser(final boolean expression) { + if (!expression) { + throw new SecurityException("Calling user is not authorized"); + } + } + + /** * Check the requested flags, throwing if any requested flags are outside * the allowed set. * diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java index 3332143251fc..289a36f5380d 100644 --- a/core/java/com/android/internal/widget/ConversationLayout.java +++ b/core/java/com/android/internal/widget/ConversationLayout.java @@ -168,8 +168,6 @@ public class ConversationLayout extends FrameLayout private int mFacePileProtectionWidthExpanded; private boolean mImportantConversation; private TextView mUnreadBadge; - private ViewGroup mAppOps; - private Rect mAppOpsTouchRect = new Rect(); private View mFeedbackIcon; private float mMinTouchSize; private Icon mConversationIcon; @@ -214,7 +212,6 @@ public class ConversationLayout extends FrameLayout mConversationIconView = findViewById(R.id.conversation_icon); mConversationIconContainer = findViewById(R.id.conversation_icon_container); mIcon = findViewById(R.id.icon); - mAppOps = findViewById(com.android.internal.R.id.app_ops); mFeedbackIcon = findViewById(com.android.internal.R.id.feedback); mMinTouchSize = 48 * getResources().getDisplayMetrics().density; mImportanceRingView = findViewById(R.id.conversation_icon_badge_ring); @@ -1174,43 +1171,6 @@ public class ConversationLayout extends FrameLayout }); } mTouchDelegate.clear(); - if (mAppOps.getWidth() > 0) { - - // Let's increase the touch size of the app ops view if it's here - mAppOpsTouchRect.set( - mAppOps.getLeft(), - mAppOps.getTop(), - mAppOps.getRight(), - mAppOps.getBottom()); - for (int i = 0; i < mAppOps.getChildCount(); i++) { - View child = mAppOps.getChildAt(i); - if (child.getVisibility() == GONE) { - continue; - } - // Make sure each child has at least a minTouchSize touch target around it - float childTouchLeft = child.getLeft() + child.getWidth() / 2.0f - - mMinTouchSize / 2.0f; - float childTouchRight = childTouchLeft + mMinTouchSize; - mAppOpsTouchRect.left = (int) Math.min(mAppOpsTouchRect.left, - mAppOps.getLeft() + childTouchLeft); - mAppOpsTouchRect.right = (int) Math.max(mAppOpsTouchRect.right, - mAppOps.getLeft() + childTouchRight); - } - - // Increase the height - int heightIncrease = 0; - if (mAppOpsTouchRect.height() < mMinTouchSize) { - heightIncrease = (int) Math.ceil((mMinTouchSize - mAppOpsTouchRect.height()) - / 2.0f); - } - mAppOpsTouchRect.inset(0, -heightIncrease); - - getRelativeTouchRect(mAppOpsTouchRect, mAppOps); - - // Extend the size of the app opps to be at least 48dp - mTouchDelegate.add(new TouchDelegate(mAppOpsTouchRect, mAppOps)); - - } if (mFeedbackIcon.getVisibility() == VISIBLE) { updateFeedbackIconMargins(); float width = Math.max(mMinTouchSize, mFeedbackIcon.getWidth()); @@ -1240,13 +1200,7 @@ public class ConversationLayout extends FrameLayout private void updateFeedbackIconMargins() { MarginLayoutParams lp = (MarginLayoutParams) mFeedbackIcon.getLayoutParams(); - if (mAppOps.getWidth() == 0) { - lp.setMarginStart(mNotificationHeaderSeparatingMargin); - } else { - float width = Math.max(mMinTouchSize, mFeedbackIcon.getWidth()); - int horizontalMargin = (int) ((width - mFeedbackIcon.getWidth()) / 2); - lp.setMarginStart(horizontalMargin); - } + lp.setMarginStart(mNotificationHeaderSeparatingMargin); mFeedbackIcon.setLayoutParams(lp); } diff --git a/core/jni/android_media_AudioDeviceAttributes.cpp b/core/jni/android_media_AudioDeviceAttributes.cpp index e79c95edbeb5..2a16dce99125 100644 --- a/core/jni/android_media_AudioDeviceAttributes.cpp +++ b/core/jni/android_media_AudioDeviceAttributes.cpp @@ -31,7 +31,7 @@ jint createAudioDeviceAttributesFromNative(JNIEnv *env, jobject *jAudioDeviceAtt const AudioDeviceTypeAddr *devTypeAddr) { jint jStatus = (jint)AUDIO_JAVA_SUCCESS; jint jNativeType = (jint)devTypeAddr->mType; - ScopedLocalRef<jstring> jAddress(env, env->NewStringUTF(devTypeAddr->mAddress.data())); + ScopedLocalRef<jstring> jAddress(env, env->NewStringUTF(devTypeAddr->getAddress())); *jAudioDeviceAttributes = env->NewObject(gAudioDeviceAttributesClass, gAudioDeviceAttributesCstor, jNativeType, jAddress.get()); diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index 1f625443c96e..3f39478ffd43 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -172,6 +172,8 @@ static struct { jmethodID postRecordConfigEventFromNative; } gAudioPolicyEventHandlerMethods; +static struct { jmethodID add; } gListMethods; + // // JNI Initialization for OpenSLES routing // @@ -310,7 +312,7 @@ static int _check_AudioSystem_Command(const char* caller, status_t status) static jint getVectorOfAudioDeviceTypeAddr(JNIEnv *env, jintArray deviceTypes, jobjectArray deviceAddresses, - Vector<AudioDeviceTypeAddr> &audioDeviceTypeAddrVector) { + AudioDeviceTypeAddrVector &audioDeviceTypeAddrVector) { if (deviceTypes == nullptr || deviceAddresses == nullptr) { return (jint)AUDIO_JAVA_BAD_VALUE; } @@ -337,7 +339,7 @@ static jint getVectorOfAudioDeviceTypeAddr(JNIEnv *env, jintArray deviceTypes, } const char *address = env->GetStringUTFChars((jstring)addrJobj, NULL); AudioDeviceTypeAddr dev = AudioDeviceTypeAddr(typesPtr[i], address); - audioDeviceTypeAddrVector.add(dev); + audioDeviceTypeAddrVector.push_back(dev); env->ReleaseStringUTFChars((jstring)addrJobj, address); } env->ReleaseIntArrayElements(deviceTypes, typesPtr, 0); @@ -2062,7 +2064,7 @@ exit: static jint android_media_AudioSystem_setUidDeviceAffinities(JNIEnv *env, jobject clazz, jint uid, jintArray deviceTypes, jobjectArray deviceAddresses) { - Vector<AudioDeviceTypeAddr> deviceVector; + AudioDeviceTypeAddrVector deviceVector; jint results = getVectorOfAudioDeviceTypeAddr(env, deviceTypes, deviceAddresses, deviceVector); if (results != NO_ERROR) { return results; @@ -2080,7 +2082,7 @@ static jint android_media_AudioSystem_removeUidDeviceAffinities(JNIEnv *env, job static jint android_media_AudioSystem_setUserIdDeviceAffinities(JNIEnv *env, jobject clazz, jint userId, jintArray deviceTypes, jobjectArray deviceAddresses) { - Vector<AudioDeviceTypeAddr> deviceVector; + AudioDeviceTypeAddrVector deviceVector; jint results = getVectorOfAudioDeviceTypeAddr(env, deviceTypes, deviceAddresses, deviceVector); if (results != NO_ERROR) { return results; @@ -2361,46 +2363,48 @@ android_media_AudioSystem_isCallScreeningModeSupported(JNIEnv *env, jobject thiz return AudioSystem::isCallScreenModeSupported(); } -static jint -android_media_AudioSystem_setPreferredDeviceForStrategy(JNIEnv *env, jobject thiz, - jint strategy, jint deviceType, jstring deviceAddress) { - - const char *c_address = env->GetStringUTFChars(deviceAddress, NULL); +static jint android_media_AudioSystem_setDevicesRoleForStrategy(JNIEnv *env, jobject thiz, + jint strategy, jint role, + jintArray jDeviceTypes, + jobjectArray jDeviceAddresses) { + AudioDeviceTypeAddrVector nDevices; + jint results = getVectorOfAudioDeviceTypeAddr(env, jDeviceTypes, jDeviceAddresses, nDevices); + if (results != NO_ERROR) { + return results; + } int status = check_AudioSystem_Command( - AudioSystem::setPreferredDeviceForStrategy((product_strategy_t) strategy, - AudioDeviceTypeAddr(deviceType, c_address))); - env->ReleaseStringUTFChars(deviceAddress, c_address); + AudioSystem::setDevicesRoleForStrategy((product_strategy_t)strategy, + (device_role_t)role, nDevices)); return (jint) status; } -static jint -android_media_AudioSystem_removePreferredDeviceForStrategy(JNIEnv *env, jobject thiz, jint strategy) -{ - return (jint) check_AudioSystem_Command( - AudioSystem::removePreferredDeviceForStrategy((product_strategy_t) strategy)); +static jint android_media_AudioSystem_removeDevicesRoleForStrategy(JNIEnv *env, jobject thiz, + jint strategy, jint role) { + return (jint)check_AudioSystem_Command( + AudioSystem::removeDevicesRoleForStrategy((product_strategy_t)strategy, + (device_role_t)role)); } -static jint -android_media_AudioSystem_getPreferredDeviceForStrategy(JNIEnv *env, jobject thiz, - jint strategy, jobjectArray jDeviceArray) -{ - if (jDeviceArray == nullptr || env->GetArrayLength(jDeviceArray) != 1) { - ALOGE("%s invalid array to store AudioDeviceAttributes", __FUNCTION__); - return (jint)AUDIO_JAVA_BAD_VALUE; - } - - AudioDeviceTypeAddr elDevice; +static jint android_media_AudioSystem_getDevicesForRoleAndStrategy(JNIEnv *env, jobject thiz, + jint strategy, jint role, + jobject jDevices) { + AudioDeviceTypeAddrVector nDevices; status_t status = check_AudioSystem_Command( - AudioSystem::getPreferredDeviceForStrategy((product_strategy_t) strategy, elDevice)); + AudioSystem::getDevicesForRoleAndStrategy((product_strategy_t)strategy, + (device_role_t)role, nDevices)); if (status != NO_ERROR) { return (jint) status; } - jobject jAudioDeviceAttributes = NULL; - jint jStatus = createAudioDeviceAttributesFromNative(env, &jAudioDeviceAttributes, &elDevice); - if (jStatus == AUDIO_JAVA_SUCCESS) { - env->SetObjectArrayElement(jDeviceArray, 0, jAudioDeviceAttributes); + for (const auto &device : nDevices) { + jobject jAudioDeviceAttributes = NULL; + jint jStatus = createAudioDeviceAttributesFromNative(env, &jAudioDeviceAttributes, &device); + if (jStatus != AUDIO_JAVA_SUCCESS) { + return jStatus; + } + env->CallBooleanMethod(jDevices, gListMethods.add, jAudioDeviceAttributes); + env->DeleteLocalRef(jAudioDeviceAttributes); } - return jStatus; + return AUDIO_JAVA_SUCCESS; } static jint @@ -2548,12 +2552,12 @@ static const JNINativeMethod gMethods[] = {"setAudioHalPids", "([I)I", (void *)android_media_AudioSystem_setAudioHalPids}, {"isCallScreeningModeSupported", "()Z", (void *)android_media_AudioSystem_isCallScreeningModeSupported}, - {"setPreferredDeviceForStrategy", "(IILjava/lang/String;)I", - (void *)android_media_AudioSystem_setPreferredDeviceForStrategy}, - {"removePreferredDeviceForStrategy", "(I)I", - (void *)android_media_AudioSystem_removePreferredDeviceForStrategy}, - {"getPreferredDeviceForStrategy", "(I[Landroid/media/AudioDeviceAttributes;)I", - (void *)android_media_AudioSystem_getPreferredDeviceForStrategy}, + {"setDevicesRoleForStrategy", "(II[I[Ljava/lang/String;)I", + (void *)android_media_AudioSystem_setDevicesRoleForStrategy}, + {"removeDevicesRoleForStrategy", "(II)I", + (void *)android_media_AudioSystem_removeDevicesRoleForStrategy}, + {"getDevicesForRoleAndStrategy", "(IILjava/util/List;)I", + (void *)android_media_AudioSystem_getDevicesForRoleAndStrategy}, {"getDevicesForAttributes", "(Landroid/media/AudioAttributes;[Landroid/media/AudioDeviceAttributes;)I", (void *)android_media_AudioSystem_getDevicesForAttributes}, @@ -2755,6 +2759,9 @@ int register_android_media_AudioSystem(JNIEnv *env) gMidAudioRecordRoutingProxy_release = android::GetMethodIDOrDie(env, gClsAudioRecordRoutingProxy, "native_release", "()V"); + jclass listClass = FindClassOrDie(env, "java/util/List"); + gListMethods.add = GetMethodIDOrDie(env, listClass, "add", "(Ljava/lang/Object;)Z"); + AudioSystem::addErrorCallback(android_media_AudioSystem_error_callback); RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods)); diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto index 1014fbb73877..0d65bd1cf9bb 100644 --- a/core/proto/android/app/settings_enums.proto +++ b/core/proto/android/app/settings_enums.proto @@ -744,6 +744,41 @@ enum Action { // CATEGORY: SETTINGS // OS: R ACTION_CONFIRM_SIM_DELETION_OFF = 1739; + + // ACTION: Settings > System > Gestures > Double tap > Toggle on Double tap + // CATEGORY: SETTINGS + // OS: S + ACTION_COLUMBUS_ENABLED = 1740; + + // ACTION: Settings > System > Gestures > Double tap > Toggle off Double tap + // CATEGORY: SETTINGS + // OS: S + ACTION_COLUMBUS_DISABLED = 1741; + + // ACTION: Settings > System > Gestures > Double tap > Invoke Assistant + // CATEGORY: SETTINGS + // OS: S + ACTION_COLUMBUS_ACTION_ASSISTANT = 1742; + + // ACTION: Settings > System > Gestures > Double tap > Take screenshot + // CATEGORY: SETTINGS + // OS: S + ACTION_COLUMBUS_ACTION_SCREENSHOT = 1743; + + // ACTION: Settings > System > Gestures > Double tap > Play and pause + // CATEGORY: SETTINGS + // OS: S + ACTION_COLUMBUS_ACTION_PLAY_PAUSE = 1744; + + // ACTION: Settings > System > Gestures > Double tap > Open app overview + // CATEGORY: SETTINGS + // OS: S + ACTION_COLUMBUS_ACTION_OVERVIEW = 1745; + + // ACTION: Settings > System > Gestures > Double tap > Open notification shade + // CATEGORY: SETTINGS + // OS: S + ACTION_COLUMBUS_ACTION_NOTIFICATION_SHADE = 1746; } /** diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index edb972730f69..32c1e4a1411c 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -558,6 +558,7 @@ <protected-broadcast android:name="android.os.action.ACTION_EFFECTS_SUPPRESSOR_CHANGED" /> <protected-broadcast android:name="android.app.action.NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED" /> <protected-broadcast android:name="android.app.action.NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED" /> + <protected-broadcast android:name="android.app.action.NOTIFICATION_LISTENER_ENABLED_CHANGED" /> <protected-broadcast android:name="android.app.action.APP_BLOCK_STATE_CHANGED" /> <protected-broadcast android:name="android.permission.GET_APP_GRANTED_URI_PERMISSIONS" /> diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml index d22a19faa52b..9a1b592c895a 100644 --- a/core/res/res/layout/notification_template_header.xml +++ b/core/res/res/layout/notification_template_header.xml @@ -160,43 +160,6 @@ android:visibility="gone" android:contentDescription="@string/notification_work_profile_content_description" /> - <LinearLayout - android:id="@+id/app_ops" - android:layout_height="match_parent" - android:layout_width="wrap_content" - android:layout_marginStart="6dp" - android:background="?android:selectableItemBackgroundBorderless" - android:orientation="horizontal"> - <ImageView - android:id="@+id/camera" - android:layout_width="?attr/notificationHeaderIconSize" - android:layout_height="?attr/notificationHeaderIconSize" - android:src="@drawable/ic_camera" - android:visibility="gone" - android:focusable="false" - android:contentDescription="@string/notification_appops_camera_active" - /> - <ImageView - android:id="@+id/mic" - android:layout_width="?attr/notificationHeaderIconSize" - android:layout_height="?attr/notificationHeaderIconSize" - android:src="@drawable/ic_mic" - android:layout_marginStart="4dp" - android:visibility="gone" - android:focusable="false" - android:contentDescription="@string/notification_appops_microphone_active" - /> - <ImageView - android:id="@+id/overlay" - android:layout_width="?attr/notificationHeaderIconSize" - android:layout_height="?attr/notificationHeaderIconSize" - android:src="@drawable/ic_alert_window_layer" - android:layout_marginStart="4dp" - android:visibility="gone" - android:focusable="false" - android:contentDescription="@string/notification_appops_overlay_active" - /> - </LinearLayout> <include layout="@layout/notification_material_media_transfer_action" android:id="@+id/media_seamless" diff --git a/core/res/res/values/cross_profile_apps.xml b/core/res/res/values/cross_profile_apps.xml index ab6f20db0694..3688c3eb940b 100644 --- a/core/res/res/values/cross_profile_apps.xml +++ b/core/res/res/values/cross_profile_apps.xml @@ -17,7 +17,7 @@ <resources> <!-- A collection of apps that have been pre-approved for cross-profile communication. - These will not require admin consent, but will still require user consent during provisioning. + These will not require admin or user consent. --> <string-array translatable="false" name="cross_profile_apps"> </string-array> diff --git a/core/res/res/xml/power_profile.xml b/core/res/res/xml/power_profile.xml index d8ec72f33ddc..166edca3d046 100644 --- a/core/res/res/xml/power_profile.xml +++ b/core/res/res/xml/power_profile.xml @@ -20,7 +20,7 @@ <device name="Android"> <!-- Most values are the incremental current used by a feature, in mA (measured at nominal voltage). - The default values are deliberately incorrect dummy values. + The default values are deliberately incorrect values. OEM's must measure and provide actual values before shipping a device. Example real-world values are given in comments, but they diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java index 000e870369db..896a53486311 100644 --- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java +++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java @@ -25,14 +25,14 @@ import static android.view.Display.INVALID_DISPLAY; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.testng.Assert.assertFalse; import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityThread; +import android.app.ActivityThread.ActivityClientRecord; import android.app.IApplicationThread; import android.app.PictureInPictureParams; import android.app.ResourcesManager; @@ -114,11 +114,12 @@ public class ActivityThreadTest { final ActivityThread activityThread = activity.getActivityThread(); InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { activityThread.executeTransaction(newResumeTransaction(activity)); - assertNull(activityThread.performResumeActivity(activity.getActivityToken(), - true /* finalStateRequest */, "test")); + final ActivityClientRecord r = getActivityClientRecord(activity); + assertFalse(activityThread.performResumeActivity(r, true /* finalStateRequest */, + "test")); - assertNull(activityThread.performResumeActivity(activity.getActivityToken(), - false /* finalStateRequest */, "test")); + assertFalse(activityThread.performResumeActivity(r, false /* finalStateRequest */, + "test")); }); } @@ -244,20 +245,18 @@ public class ActivityThreadTest { newerConfig.orientation = orientation == ORIENTATION_LANDSCAPE ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE; newerConfig.seq = seq + 2; - activityThread.updatePendingActivityConfiguration(activity.getActivityToken(), - newerConfig); + final ActivityClientRecord r = getActivityClientRecord(activity); + activityThread.updatePendingActivityConfiguration(r, newerConfig); final Configuration olderConfig = new Configuration(); olderConfig.orientation = orientation; olderConfig.seq = seq + 1; - activityThread.handleActivityConfigurationChanged(activity.getActivityToken(), - olderConfig, INVALID_DISPLAY); + activityThread.handleActivityConfigurationChanged(r, olderConfig, INVALID_DISPLAY); assertEquals(numOfConfig, activity.mNumOfConfigChanges); assertEquals(olderConfig.orientation, activity.mConfig.orientation); - activityThread.handleActivityConfigurationChanged(activity.getActivityToken(), - newerConfig, INVALID_DISPLAY); + activityThread.handleActivityConfigurationChanged(r, newerConfig, INVALID_DISPLAY); assertEquals(numOfConfig + 1, activity.mNumOfConfigChanges); assertEquals(newerConfig.orientation, activity.mConfig.orientation); }); @@ -274,7 +273,7 @@ public class ActivityThreadTest { config.seq = BASE_SEQ; config.orientation = ORIENTATION_PORTRAIT; - activityThread.handleActivityConfigurationChanged(activity.getActivityToken(), + activityThread.handleActivityConfigurationChanged(getActivityClientRecord(activity), config, INVALID_DISPLAY); }); @@ -335,8 +334,8 @@ public class ActivityThreadTest { config.seq = BASE_SEQ; config.orientation = ORIENTATION_PORTRAIT; - activityThread.handleActivityConfigurationChanged(activity.getActivityToken(), - config, INVALID_DISPLAY); + final ActivityClientRecord r = getActivityClientRecord(activity); + activityThread.handleActivityConfigurationChanged(r, config, INVALID_DISPLAY); }); final int numOfConfig = activity.mNumOfConfigChanges; @@ -513,9 +512,10 @@ public class ActivityThreadTest { startIntent.putExtra(TestActivity.PIP_REQUESTED_OVERRIDE_ENTER, true); final TestActivity activity = mActivityTestRule.launchActivity(startIntent); final ActivityThread activityThread = activity.getActivityThread(); + final ActivityClientRecord r = getActivityClientRecord(activity); InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { - activityThread.handlePictureInPictureRequested(activity.getActivityToken()); + activityThread.handlePictureInPictureRequested(r); }); assertTrue(activity.pipRequested()); @@ -528,9 +528,10 @@ public class ActivityThreadTest { startIntent.putExtra(TestActivity.PIP_REQUESTED_OVERRIDE_SKIP, true); final TestActivity activity = mActivityTestRule.launchActivity(startIntent); final ActivityThread activityThread = activity.getActivityThread(); + final ActivityClientRecord r = getActivityClientRecord(activity); InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { - activityThread.handlePictureInPictureRequested(activity.getActivityToken()); + activityThread.handlePictureInPictureRequested(r); }); assertTrue(activity.pipRequested()); @@ -541,9 +542,10 @@ public class ActivityThreadTest { public void testHandlePictureInPictureRequested_notOverridden() { final TestActivity activity = mActivityTestRule.launchActivity(new Intent()); final ActivityThread activityThread = activity.getActivityThread(); + final ActivityClientRecord r = getActivityClientRecord(activity); InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { - activityThread.handlePictureInPictureRequested(activity.getActivityToken()); + activityThread.handlePictureInPictureRequested(r); }); assertTrue(activity.pipRequested()); @@ -552,8 +554,9 @@ public class ActivityThreadTest { } /** - * Calls {@link ActivityThread#handleActivityConfigurationChanged(IBinder, Configuration, int)} - * to try to push activity configuration to the activity for the given sequence number. + * Calls {@link ActivityThread#handleActivityConfigurationChanged(ActivityClientRecord, + * Configuration, int)} to try to push activity configuration to the activity for the given + * sequence number. * <p> * It uses orientation to push the configuration and it tries a different orientation if the * first attempt doesn't make through, to rule out the possibility that the previous @@ -566,13 +569,13 @@ public class ActivityThreadTest { */ private int applyConfigurationChange(TestActivity activity, int seq) { final ActivityThread activityThread = activity.getActivityThread(); + final ActivityClientRecord r = getActivityClientRecord(activity); final int numOfConfig = activity.mNumOfConfigChanges; Configuration config = new Configuration(); config.orientation = ORIENTATION_PORTRAIT; config.seq = seq; - activityThread.handleActivityConfigurationChanged(activity.getActivityToken(), config, - INVALID_DISPLAY); + activityThread.handleActivityConfigurationChanged(r, config, INVALID_DISPLAY); if (activity.mNumOfConfigChanges > numOfConfig) { return config.seq; @@ -581,12 +584,17 @@ public class ActivityThreadTest { config = new Configuration(); config.orientation = ORIENTATION_LANDSCAPE; config.seq = seq + 1; - activityThread.handleActivityConfigurationChanged(activity.getActivityToken(), config, - INVALID_DISPLAY); + activityThread.handleActivityConfigurationChanged(r, config, INVALID_DISPLAY); return config.seq; } + private static ActivityClientRecord getActivityClientRecord(Activity activity) { + final ActivityThread thread = activity.getActivityThread(); + final IBinder token = activity.getActivityToken(); + return thread.getActivityClient(token); + } + private static ClientTransaction newRelaunchResumeTransaction(Activity activity) { final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(null, null, 0, new MergedConfiguration(), false /* preserveWindow */); diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java index 3c32c71cf961..6a0105cf7ff0 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java @@ -32,11 +32,12 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.inOrder; 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.verify; import static org.mockito.Mockito.when; +import android.app.Activity; import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; import android.app.servertransaction.ActivityLifecycleItem.LifecycleState; @@ -225,6 +226,7 @@ public class TransactionExecutorTests { when(callback2.getPostExecutionState()).thenReturn(UNDEFINED); ActivityLifecycleItem stateRequest = mock(ActivityLifecycleItem.class); IBinder token = mock(IBinder.class); + when(mTransactionHandler.getActivity(token)).thenReturn(mock(Activity.class)); ClientTransaction transaction = ClientTransaction.obtain(null /* client */, token /* activityToken */); @@ -236,9 +238,9 @@ public class TransactionExecutorTests { mExecutor.execute(transaction); InOrder inOrder = inOrder(mTransactionHandler, callback1, callback2, stateRequest); - inOrder.verify(callback1, times(1)).execute(eq(mTransactionHandler), eq(token), any()); - inOrder.verify(callback2, times(1)).execute(eq(mTransactionHandler), eq(token), any()); - inOrder.verify(stateRequest, times(1)).execute(eq(mTransactionHandler), eq(token), any()); + inOrder.verify(callback1).execute(eq(mTransactionHandler), eq(token), any()); + inOrder.verify(callback2).execute(eq(mTransactionHandler), eq(token), any()); + inOrder.verify(stateRequest).execute(eq(mTransactionHandler), eq(mClientRecord), any()); } @Test @@ -273,7 +275,7 @@ public class TransactionExecutorTests { // The launch transaction should not be executed because its token is in the // to-be-destroyed container. - verify(launchItem, times(0)).execute(any(), any(), any()); + verify(launchItem, never()).execute(any(), any(), any()); // After the destroy transaction has been executed, the token should be removed. mExecutor.execute(destroyTransaction); @@ -282,6 +284,8 @@ public class TransactionExecutorTests { @Test public void testActivityResultRequiredStateResolution() { + when(mTransactionHandler.getActivity(any())).thenReturn(mock(Activity.class)); + PostExecItem postExecItem = new PostExecItem(ON_RESUME); IBinder token = mock(IBinder.class); @@ -292,12 +296,12 @@ public class TransactionExecutorTests { // Verify resolution that should get to onPause mClientRecord.setState(ON_RESUME); mExecutor.executeCallbacks(transaction); - verify(mExecutor, times(1)).cycleToPath(eq(mClientRecord), eq(ON_PAUSE), eq(transaction)); + verify(mExecutor).cycleToPath(eq(mClientRecord), eq(ON_PAUSE), eq(transaction)); // Verify resolution that should get to onStart mClientRecord.setState(ON_STOP); mExecutor.executeCallbacks(transaction); - verify(mExecutor, times(1)).cycleToPath(eq(mClientRecord), eq(ON_START), eq(transaction)); + verify(mExecutor).cycleToPath(eq(mClientRecord), eq(ON_START), eq(transaction)); } @Test @@ -433,6 +437,38 @@ public class TransactionExecutorTests { mExecutorHelper.getClosestPreExecutionState(mClientRecord, ON_RESUME)); } + @Test(expected = IllegalArgumentException.class) + public void testActivityItemNullRecordThrowsException() { + final ActivityTransactionItem activityItem = mock(ActivityTransactionItem.class); + when(activityItem.getPostExecutionState()).thenReturn(UNDEFINED); + final IBinder token = mock(IBinder.class); + final ClientTransaction transaction = ClientTransaction.obtain(null /* client */, + token /* activityToken */); + transaction.addCallback(activityItem); + when(mTransactionHandler.getActivityClient(token)).thenReturn(null); + + mExecutor.executeCallbacks(transaction); + } + + @Test + public void testActivityItemExecute() { + final IBinder token = mock(IBinder.class); + final ClientTransaction transaction = ClientTransaction.obtain(null /* client */, + token /* activityToken */); + final ActivityTransactionItem activityItem = mock(ActivityTransactionItem.class); + when(activityItem.getPostExecutionState()).thenReturn(UNDEFINED); + transaction.addCallback(activityItem); + final ActivityLifecycleItem stateRequest = mock(ActivityLifecycleItem.class); + transaction.setLifecycleStateRequest(stateRequest); + when(mTransactionHandler.getActivity(token)).thenReturn(mock(Activity.class)); + + mExecutor.execute(transaction); + + final InOrder inOrder = inOrder(activityItem, stateRequest); + inOrder.verify(activityItem).execute(eq(mTransactionHandler), eq(mClientRecord), any()); + inOrder.verify(stateRequest).execute(eq(mTransactionHandler), eq(mClientRecord), any()); + } + private static int[] shuffledArray(int[] inputArray) { final List<Integer> list = Arrays.stream(inputArray).boxed().collect(Collectors.toList()); Collections.shuffle(list); @@ -489,13 +525,13 @@ public class TransactionExecutorTests { public static final Parcelable.Creator<StubItem> CREATOR = new Parcelable.Creator<StubItem>() { - public StubItem createFromParcel(Parcel in) { - return new StubItem(in); - } - - public StubItem[] newArray(int size) { - return new StubItem[size]; - } - }; + public StubItem createFromParcel(Parcel in) { + return new StubItem(in); + } + + public StubItem[] newArray(int size) { + return new StubItem[size]; + } + }; } } diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java index 1cdc75aa1f40..3f2d0f134443 100644 --- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java +++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java @@ -176,27 +176,27 @@ public class ActivityThreadClientTest { } private void startActivity(ActivityClientRecord r) { - mThread.handleStartActivity(r.token, null /* pendingActions */); + mThread.handleStartActivity(r, null /* pendingActions */); } private void resumeActivity(ActivityClientRecord r) { - mThread.handleResumeActivity(r.token, true /* finalStateRequest */, + mThread.handleResumeActivity(r, true /* finalStateRequest */, true /* isForward */, "test"); } private void pauseActivity(ActivityClientRecord r) { - mThread.handlePauseActivity(r.token, false /* finished */, + mThread.handlePauseActivity(r, false /* finished */, false /* userLeaving */, 0 /* configChanges */, null /* pendingActions */, "test"); } private void stopActivity(ActivityClientRecord r) { - mThread.handleStopActivity(r.token, 0 /* configChanges */, + mThread.handleStopActivity(r, 0 /* configChanges */, new PendingTransactionActions(), false /* finalStateRequest */, "test"); } private void destroyActivity(ActivityClientRecord r) { - mThread.handleDestroyActivity(r.token, true /* finishing */, 0 /* configChanges */, + mThread.handleDestroyActivity(r, true /* finishing */, 0 /* configChanges */, false /* getNonConfigInstance */, "test"); } diff --git a/drm/java/android/drm/DrmManagerClient.java b/drm/java/android/drm/DrmManagerClient.java index ba3ebddd4b86..4ec752a6dd9e 100644 --- a/drm/java/android/drm/DrmManagerClient.java +++ b/drm/java/android/drm/DrmManagerClient.java @@ -751,7 +751,7 @@ public class DrmManagerClient implements AutoCloseable { /** * Removes all the rights information of every DRM plug-in (agent) associated with - * the DRM framework. Will be used during a master reset. + * the DRM framework. * * @return ERROR_NONE for success; ERROR_UNKNOWN for failure. */ diff --git a/libs/hostgraphics/Android.bp b/libs/hostgraphics/Android.bp index e713b98b867e..9d83e491fdc1 100644 --- a/libs/hostgraphics/Android.bp +++ b/libs/hostgraphics/Android.bp @@ -5,6 +5,10 @@ cc_library_host_static { "-Wno-unused-parameter", ], + static_libs: [ + "libbase", + ], + srcs: [ ":libui_host_common", "Fence.cpp", @@ -28,4 +32,4 @@ cc_library_host_static { enabled: true, } }, -}
\ No newline at end of file +} diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp index 2a8aa8c3e5b7..a11678189bad 100644 --- a/libs/hwui/renderthread/EglManager.cpp +++ b/libs/hwui/renderthread/EglManager.cpp @@ -238,12 +238,8 @@ EGLConfig EglManager::loadFP16Config(EGLDisplay display, SwapBehavior swapBehavi return config; } -extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); - void EglManager::initExtensions() { auto extensions = StringUtils::split(eglQueryString(mEglDisplay, EGL_EXTENSIONS)); - auto extensionsAndroid = - StringUtils::split(eglQueryStringImplementationANDROID(mEglDisplay, EGL_EXTENSIONS)); // For our purposes we don't care if EGL_BUFFER_AGE is a result of // EGL_EXT_buffer_age or EGL_KHR_partial_update as our usage is covered @@ -265,10 +261,7 @@ void EglManager::initExtensions() { EglExtensions.surfacelessContext = extensions.has("EGL_KHR_surfaceless_context"); EglExtensions.fenceSync = extensions.has("EGL_KHR_fence_sync"); EglExtensions.waitSync = extensions.has("EGL_KHR_wait_sync"); - - // EGL_ANDROID_native_fence_sync is not exposed to applications, so access - // this through the private Android-specific query instead. - EglExtensions.nativeFenceSync = extensionsAndroid.has("EGL_ANDROID_native_fence_sync"); + EglExtensions.nativeFenceSync = extensions.has("EGL_ANDROID_native_fence_sync"); } bool EglManager::hasEglContext() { diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index b2e0538fd4b8..a16e063fe969 100755 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -75,6 +75,7 @@ import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -1599,11 +1600,25 @@ public class AudioManager { @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy, @NonNull AudioDeviceAttributes device) { + return setPreferredDevicesForStrategy(strategy, Arrays.asList(device)); + } + + /** + * @hide + * Removes the preferred audio device(s) previously set with + * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or + * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}. + * @param strategy the audio strategy whose routing will be affected + * @return true if the operation was successful, false otherwise (invalid strategy, or no + * device set for example) + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + public boolean removePreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy) { Objects.requireNonNull(strategy); - Objects.requireNonNull(device); try { final int status = - getService().setPreferredDeviceForStrategy(strategy.getId(), device); + getService().removePreferredDevicesForStrategy(strategy.getId()); return status == AudioSystem.SUCCESS; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -1612,19 +1627,52 @@ public class AudioManager { /** * @hide - * Removes the preferred audio device previously set with - * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)}. + * Return the preferred device for an audio strategy, previously set with + * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or + * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)} + * @param strategy the strategy to query + * @return the preferred device for that strategy, if multiple devices are set as preferred + * devices, the first one in the list will be returned. Null will be returned if none was + * ever set or if the strategy is invalid + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @Nullable + public AudioDeviceAttributes getPreferredDeviceForStrategy( + @NonNull AudioProductStrategy strategy) { + List<AudioDeviceAttributes> devices = getPreferredDevicesForStrategy(strategy); + return devices.isEmpty() ? null : devices.get(0); + } + + /** + * @hide + * Set the preferred devices for a given strategy, i.e. the audio routing to be used by + * this audio strategy. Note that the devices may not be available at the time the preferred + * devices is set, but it will be used once made available. + * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting + * this preference for this strategy.</p> + * Note that the list of devices is not a list ranked by preference, but a list of one or more + * devices used simultaneously to output the same audio signal. * @param strategy the audio strategy whose routing will be affected - * @return true if the operation was successful, false otherwise (invalid strategy, or no - * device set for example) + * @param devices a non-empty list of the audio devices to route to when available + * @return true if the operation was successful, false otherwise */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) - public boolean removePreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy) { + public boolean setPreferredDevicesForStrategy(@NonNull AudioProductStrategy strategy, + @NonNull List<AudioDeviceAttributes> devices) { Objects.requireNonNull(strategy); + Objects.requireNonNull(devices); + if (devices.isEmpty()) { + throw new IllegalArgumentException( + "Tried to set preferred devices for strategy with a empty list"); + } + for (AudioDeviceAttributes device : devices) { + Objects.requireNonNull(device); + } try { final int status = - getService().removePreferredDeviceForStrategy(strategy.getId()); + getService().setPreferredDevicesForStrategy(strategy.getId(), devices); return status == AudioSystem.SUCCESS; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -1633,19 +1681,21 @@ public class AudioManager { /** * @hide - * Return the preferred device for an audio strategy, previously set with + * Return the preferred devices for an audio strategy, previously set with * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} + * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)} * @param strategy the strategy to query * @return the preferred device for that strategy, or null if none was ever set or if the * strategy is invalid */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) - public @Nullable AudioDeviceAttributes getPreferredDeviceForStrategy( + @NonNull + public List<AudioDeviceAttributes> getPreferredDevicesForStrategy( @NonNull AudioProductStrategy strategy) { Objects.requireNonNull(strategy); try { - return getService().getPreferredDeviceForStrategy(strategy.getId()); + return getService().getPreferredDevicesForStrategy(strategy.getId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1657,6 +1707,7 @@ public class AudioManager { * strategy. * <p>Note that this listener will only be invoked whenever * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or + * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)} * {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in * preferred device. It will not be invoked directly after registration with * {@link #addOnPreferredDeviceForStrategyChangedListener(Executor, OnPreferredDeviceForStrategyChangedListener)} @@ -1664,8 +1715,10 @@ public class AudioManager { * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes) * @see #removePreferredDeviceForStrategy(AudioProductStrategy) * @see #getPreferredDeviceForStrategy(AudioProductStrategy) + * @deprecated use #OnPreferredDevicesForStrategyChangedListener */ @SystemApi + @Deprecated public interface OnPreferredDeviceForStrategyChangedListener { /** * Called on the listener to indicate that the preferred audio device for the given @@ -1680,23 +1733,87 @@ public class AudioManager { /** * @hide + * Interface to be notified of changes in the preferred audio devices set for a given audio + * strategy. + * <p>Note that this listener will only be invoked whenever + * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or + * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)} + * {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in + * preferred device(s). It will not be invoked directly after registration with + * {@link #addOnPreferredDevicesForStrategyChangedListener( + * Executor, OnPreferredDevicesForStrategyChangedListener)} + * to indicate which strategies had preferred devices at the time of registration.</p> + * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes) + * @see #setPreferredDevicesForStrategy(AudioProductStrategy, List) + * @see #removePreferredDeviceForStrategy(AudioProductStrategy) + * @see #getPreferredDeviceForStrategy(AudioProductStrategy) + * @see #getPreferredDevicesForStrategy(AudioProductStrategy) + */ + @SystemApi + public interface OnPreferredDevicesForStrategyChangedListener { + /** + * Called on the listener to indicate that the preferred audio devices for the given + * strategy has changed. + * @param strategy the {@link AudioProductStrategy} whose preferred device changed + * @param devices a list of newly set preferred audio devices + */ + void onPreferredDevicesForStrategyChanged(@NonNull AudioProductStrategy strategy, + @NonNull List<AudioDeviceAttributes> devices); + } + + /** + * @hide * Adds a listener for being notified of changes to the strategy-preferred audio device. * @param executor * @param listener * @throws SecurityException if the caller doesn't hold the required permission + * @deprecated use {@link #addOnPreferredDevicesForStrategyChangedListener( + * Executor, AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @Deprecated public void addOnPreferredDeviceForStrategyChangedListener( @NonNull @CallbackExecutor Executor executor, @NonNull OnPreferredDeviceForStrategyChangedListener listener) throws SecurityException { + // No-op, the method is deprecated. + } + + /** + * @hide + * Removes a previously added listener of changes to the strategy-preferred audio device. + * @param listener + * @deprecated use {@link #removeOnPreferredDevicesForStrategyChangedListener( + * AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + @Deprecated + public void removeOnPreferredDeviceForStrategyChangedListener( + @NonNull OnPreferredDeviceForStrategyChangedListener listener) { + // No-op, the method is deprecated. + } + + /** + * @hide + * Adds a listener for being notified of changes to the strategy-preferred audio device. + * @param executor + * @param listener + * @throws SecurityException if the caller doesn't hold the required permission + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + public void addOnPreferredDevicesForStrategyChangedListener( + @NonNull @CallbackExecutor Executor executor, + @NonNull OnPreferredDevicesForStrategyChangedListener listener) + throws SecurityException { Objects.requireNonNull(executor); Objects.requireNonNull(listener); synchronized (mPrefDevListenerLock) { if (hasPrefDevListener(listener)) { throw new IllegalArgumentException( - "attempt to call addOnPreferredDeviceForStrategyChangedListener() " + "attempt to call addOnPreferredDevicesForStrategyChangedListener() " + "on a previously registered listener"); } // lazy initialization of the list of strategy-preferred device listener @@ -1708,10 +1825,10 @@ public class AudioManager { if (oldCbCount == 0 && mPrefDevListeners.size() > 0) { // register binder for callbacks if (mPrefDevDispatcherStub == null) { - mPrefDevDispatcherStub = new StrategyPreferredDeviceDispatcherStub(); + mPrefDevDispatcherStub = new StrategyPreferredDevicesDispatcherStub(); } try { - getService().registerStrategyPreferredDeviceDispatcher(mPrefDevDispatcherStub); + getService().registerStrategyPreferredDevicesDispatcher(mPrefDevDispatcherStub); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1726,8 +1843,8 @@ public class AudioManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) - public void removeOnPreferredDeviceForStrategyChangedListener( - @NonNull OnPreferredDeviceForStrategyChangedListener listener) { + public void removeOnPreferredDevicesForStrategyChangedListener( + @NonNull OnPreferredDevicesForStrategyChangedListener listener) { Objects.requireNonNull(listener); synchronized (mPrefDevListenerLock) { if (!removePrefDevListener(listener)) { @@ -1738,7 +1855,7 @@ public class AudioManager { if (mPrefDevListeners.size() == 0) { // unregister binder for callbacks try { - getService().unregisterStrategyPreferredDeviceDispatcher( + getService().unregisterStrategyPreferredDevicesDispatcher( mPrefDevDispatcherStub); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -1760,23 +1877,23 @@ public class AudioManager { private @Nullable ArrayList<PrefDevListenerInfo> mPrefDevListeners; private static class PrefDevListenerInfo { - final @NonNull OnPreferredDeviceForStrategyChangedListener mListener; + final @NonNull OnPreferredDevicesForStrategyChangedListener mListener; final @NonNull Executor mExecutor; - PrefDevListenerInfo(OnPreferredDeviceForStrategyChangedListener listener, Executor exe) { + PrefDevListenerInfo(OnPreferredDevicesForStrategyChangedListener listener, Executor exe) { mListener = listener; mExecutor = exe; } } @GuardedBy("mPrefDevListenerLock") - private StrategyPreferredDeviceDispatcherStub mPrefDevDispatcherStub; + private StrategyPreferredDevicesDispatcherStub mPrefDevDispatcherStub; - private final class StrategyPreferredDeviceDispatcherStub - extends IStrategyPreferredDeviceDispatcher.Stub { + private final class StrategyPreferredDevicesDispatcherStub + extends IStrategyPreferredDevicesDispatcher.Stub { @Override - public void dispatchPrefDeviceChanged(int strategyId, - @Nullable AudioDeviceAttributes device) { + public void dispatchPrefDevicesChanged(int strategyId, + @NonNull List<AudioDeviceAttributes> devices) { // make a shallow copy of listeners so callback is not executed under lock final ArrayList<PrefDevListenerInfo> prefDevListeners; synchronized (mPrefDevListenerLock) { @@ -1791,7 +1908,7 @@ public class AudioManager { try { for (PrefDevListenerInfo info : prefDevListeners) { info.mExecutor.execute(() -> - info.mListener.onPreferredDeviceForStrategyChanged(strategy, device)); + info.mListener.onPreferredDevicesForStrategyChanged(strategy, devices)); } } finally { Binder.restoreCallingIdentity(ident); @@ -1801,7 +1918,7 @@ public class AudioManager { @GuardedBy("mPrefDevListenerLock") private @Nullable PrefDevListenerInfo getPrefDevListenerInfo( - OnPreferredDeviceForStrategyChangedListener listener) { + OnPreferredDevicesForStrategyChangedListener listener) { if (mPrefDevListeners == null) { return null; } @@ -1814,7 +1931,7 @@ public class AudioManager { } @GuardedBy("mPrefDevListenerLock") - private boolean hasPrefDevListener(OnPreferredDeviceForStrategyChangedListener listener) { + private boolean hasPrefDevListener(OnPreferredDevicesForStrategyChangedListener listener) { return getPrefDevListenerInfo(listener) != null; } @@ -1822,7 +1939,7 @@ public class AudioManager { /** * @return true if the listener was removed from the list */ - private boolean removePrefDevListener(OnPreferredDeviceForStrategyChangedListener listener) { + private boolean removePrefDevListener(OnPreferredDevicesForStrategyChangedListener listener) { final PrefDevListenerInfo infoToRemove = getPrefDevListenerInfo(listener); if (infoToRemove != null) { mPrefDevListeners.remove(infoToRemove); diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 5fe5c0580b0c..243ec1f1fcd0 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -32,6 +32,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; @@ -1377,6 +1378,11 @@ public class AudioSystem /** @hide */ public static final int FOR_VIBRATE_RINGING = 7; private static final int NUM_FORCE_USE = 8; + // Device role in audio policy + public static final int DEVICE_ROLE_NONE = 0; + public static final int DEVICE_ROLE_PREFERRED = 1; + public static final int DEVICE_ROLE_DISABLED = 2; + /** @hide */ public static String forceUseUsageToString(int usage) { switch (usage) { @@ -1697,47 +1703,58 @@ public class AudioSystem /** * @hide - * Sets the preferred device to use for a given audio strategy in the audio policy engine + * Set device as role for product strategy. * @param strategy the id of the strategy to configure - * @param device the device type and address to route to when available + * @param role the role of the devices + * @param devices the list of devices to be set as role for the given strategy * @return {@link #SUCCESS} if successfully set */ - public static int setPreferredDeviceForStrategy( - int strategy, @NonNull AudioDeviceAttributes device) { - return setPreferredDeviceForStrategy(strategy, - AudioDeviceInfo.convertDeviceTypeToInternalDevice(device.getType()), - device.getAddress()); + public static int setDevicesRoleForStrategy( + int strategy, int role, @NonNull List<AudioDeviceAttributes> devices) { + if (devices.isEmpty()) { + return BAD_VALUE; + } + int[] types = new int[devices.size()]; + String[] addresses = new String[devices.size()]; + for (int i = 0; i < devices.size(); ++i) { + types[i] = AudioDeviceInfo.convertDeviceTypeToInternalDevice(devices.get(i).getType()); + addresses[i] = devices.get(i).getAddress(); + } + return setDevicesRoleForStrategy(strategy, role, types, addresses); } + /** * @hide - * Set device routing per product strategy. + * Set device as role for product strategy. * @param strategy the id of the strategy to configure - * @param deviceType the native device type, NOT AudioDeviceInfo types - * @param deviceAddress the address of the device + * @param role the role of the devices + * @param types all device types + * @param addresses all device addresses * @return {@link #SUCCESS} if successfully set */ - private static native int setPreferredDeviceForStrategy( - int strategy, int deviceType, String deviceAddress); + private static native int setDevicesRoleForStrategy( + int strategy, int role, @NonNull int[] types, @NonNull String[] addresses); /** * @hide - * Remove preferred routing for the strategy + * Remove devices as role for the strategy * @param strategy the id of the strategy to configure + * @param role the role of the devices * @return {@link #SUCCESS} if successfully removed */ - public static native int removePreferredDeviceForStrategy(int strategy); + public static native int removeDevicesRoleForStrategy(int strategy, int role); /** * @hide - * Query previously set preferred device for a strategy + * Query previously set devices as role for a strategy * @param strategy the id of the strategy to query for - * @param device an array of size 1 that will contain the preferred device, or null if - * none was set + * @param role the role of the devices + * @param devices a list that will contain the devices of role * @return {@link #SUCCESS} if there is a preferred device and it was successfully retrieved * and written to the array */ - public static native int getPreferredDeviceForStrategy(int strategy, - AudioDeviceAttributes[] device); + public static native int getDevicesForRoleAndStrategy( + int strategy, int role, @NonNull List<AudioDeviceAttributes> devices); // Items shared with audio service diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 4cf236a84eb0..ef8b0edb1fe5 100755 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -29,7 +29,7 @@ import android.media.IAudioServerStateDispatcher; import android.media.IPlaybackConfigDispatcher; import android.media.IRecordingConfigDispatcher; import android.media.IRingtonePlayer; -import android.media.IStrategyPreferredDeviceDispatcher; +import android.media.IStrategyPreferredDevicesDispatcher; import android.media.IVolumeController; import android.media.IVolumeController; import android.media.PlayerBase; @@ -279,11 +279,11 @@ interface IAudioService { boolean isCallScreeningModeSupported(); - int setPreferredDeviceForStrategy(in int strategy, in AudioDeviceAttributes device); + int setPreferredDevicesForStrategy(in int strategy, in List<AudioDeviceAttributes> device); - int removePreferredDeviceForStrategy(in int strategy); + int removePreferredDevicesForStrategy(in int strategy); - AudioDeviceAttributes getPreferredDeviceForStrategy(in int strategy); + List<AudioDeviceAttributes> getPreferredDevicesForStrategy(in int strategy); List<AudioDeviceAttributes> getDevicesForAttributes(in AudioAttributes attributes); @@ -291,10 +291,10 @@ interface IAudioService { int getAllowedCapturePolicy(); - void registerStrategyPreferredDeviceDispatcher(IStrategyPreferredDeviceDispatcher dispatcher); + void registerStrategyPreferredDevicesDispatcher(IStrategyPreferredDevicesDispatcher dispatcher); - oneway void unregisterStrategyPreferredDeviceDispatcher( - IStrategyPreferredDeviceDispatcher dispatcher); + oneway void unregisterStrategyPreferredDevicesDispatcher( + IStrategyPreferredDevicesDispatcher dispatcher); oneway void setRttEnabled(in boolean rttEnabled); diff --git a/media/java/android/media/IStrategyPreferredDeviceDispatcher.aidl b/media/java/android/media/IStrategyPreferredDevicesDispatcher.aidl index b1f99e6b729e..db674c36a5c9 100644 --- a/media/java/android/media/IStrategyPreferredDeviceDispatcher.aidl +++ b/media/java/android/media/IStrategyPreferredDevicesDispatcher.aidl @@ -19,12 +19,12 @@ package android.media; import android.media.AudioDeviceAttributes; /** - * AIDL for AudioService to signal audio strategy-preferred device updates. + * AIDL for AudioService to signal audio strategy-preferred devices updates. * * {@hide} */ -oneway interface IStrategyPreferredDeviceDispatcher { +oneway interface IStrategyPreferredDevicesDispatcher { - void dispatchPrefDeviceChanged(int strategyId, in AudioDeviceAttributes device); + void dispatchPrefDevicesChanged(int strategyId, in List<AudioDeviceAttributes> devices); } diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java index 39c7682a2a74..1386cba5f9ca 100644 --- a/media/java/android/service/media/MediaBrowserService.java +++ b/media/java/android/service/media/MediaBrowserService.java @@ -684,8 +684,15 @@ public abstract class MediaBrowserService extends Service { List<MediaBrowser.MediaItem> filteredList = (flag & RESULT_FLAG_OPTION_NOT_HANDLED) != 0 ? applyOptions(list, options) : list; - final ParceledListSlice<MediaBrowser.MediaItem> pls = - filteredList == null ? null : new ParceledListSlice<>(filteredList); + final ParceledListSlice<MediaBrowser.MediaItem> pls; + if (filteredList == null) { + pls = null; + } else { + pls = new ParceledListSlice<>(filteredList); + // Limit the size of initial Parcel to prevent binder buffer overflow + // as onLoadChildren is an async binder call. + pls.setInlineCountLimit(1); + } try { connection.callbacks.onLoadChildren(parentId, pls, options); } catch (RemoteException ex) { diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp index 96961ac21a2d..45c49e58f390 100644 --- a/media/jni/audioeffect/android_media_AudioEffect.cpp +++ b/media/jni/audioeffect/android_media_AudioEffect.cpp @@ -333,7 +333,7 @@ android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_t if (deviceType != AUDIO_DEVICE_NONE) { device.mType = deviceType; ScopedUtfChars address(env, deviceAddress); - device.mAddress = address.c_str(); + device.setAddress(address.c_str()); } // create the native AudioEffect object diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt index 51e7287bfd72..f9d0d14c7335 100644 --- a/non-updatable-api/current.txt +++ b/non-updatable-api/current.txt @@ -44126,7 +44126,9 @@ package android.telecom { method public final void addExistingConnection(android.telecom.PhoneAccountHandle, android.telecom.Connection); method public final void conferenceRemoteConnections(android.telecom.RemoteConnection, android.telecom.RemoteConnection); method public final void connectionServiceFocusReleased(); + method @Nullable public final android.telecom.RemoteConference createRemoteIncomingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest); method public final android.telecom.RemoteConnection createRemoteIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); + method @Nullable public final android.telecom.RemoteConference createRemoteOutgoingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest); method public final android.telecom.RemoteConnection createRemoteOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); method public final java.util.Collection<android.telecom.Conference> getAllConferences(); method public final java.util.Collection<android.telecom.Connection> getAllConnections(); @@ -44357,6 +44359,7 @@ package android.telecom { public final class RemoteConnection { method public void abort(); + method public void addConferenceParticipants(@NonNull java.util.List<android.net.Uri>); method public void answer(); method public void disconnect(); method public android.net.Uri getAddress(); @@ -63867,7 +63870,7 @@ package java.lang.reflect { package java.math { - public class BigDecimal extends java.lang.Number implements java.lang.Comparable<java.math.BigDecimal> java.io.Serializable { + public class BigDecimal extends java.lang.Number implements java.lang.Comparable<java.math.BigDecimal> { ctor public BigDecimal(char[], int, int); ctor public BigDecimal(char[], int, int, java.math.MathContext); ctor public BigDecimal(char[]); @@ -63954,19 +63957,20 @@ package java.math { field public static final java.math.BigDecimal ZERO; } - public class BigInteger extends java.lang.Number implements java.lang.Comparable<java.math.BigInteger> java.io.Serializable { + public class BigInteger extends java.lang.Number implements java.lang.Comparable<java.math.BigInteger> { + ctor public BigInteger(byte[]); + ctor public BigInteger(int, byte[]); + ctor public BigInteger(@NonNull String, int); + ctor public BigInteger(@NonNull String); ctor public BigInteger(int, @NonNull java.util.Random); ctor public BigInteger(int, int, @NonNull java.util.Random); - ctor public BigInteger(@NonNull String); - ctor public BigInteger(@NonNull String, int); - ctor public BigInteger(int, byte[]); - ctor public BigInteger(byte[]); method @NonNull public java.math.BigInteger abs(); method @NonNull public java.math.BigInteger add(@NonNull java.math.BigInteger); method @NonNull public java.math.BigInteger and(@NonNull java.math.BigInteger); method @NonNull public java.math.BigInteger andNot(@NonNull java.math.BigInteger); method public int bitCount(); method public int bitLength(); + method public byte byteValueExact(); method @NonNull public java.math.BigInteger clearBit(int); method public int compareTo(@NonNull java.math.BigInteger); method @NonNull public java.math.BigInteger divide(@NonNull java.math.BigInteger); @@ -63977,8 +63981,10 @@ package java.math { method @NonNull public java.math.BigInteger gcd(@NonNull java.math.BigInteger); method public int getLowestSetBit(); method public int intValue(); + method public int intValueExact(); method public boolean isProbablePrime(int); method public long longValue(); + method public long longValueExact(); method @NonNull public java.math.BigInteger max(@NonNull java.math.BigInteger); method @NonNull public java.math.BigInteger min(@NonNull java.math.BigInteger); method @NonNull public java.math.BigInteger mod(@NonNull java.math.BigInteger); @@ -63995,6 +64001,7 @@ package java.math { method @NonNull public java.math.BigInteger setBit(int); method @NonNull public java.math.BigInteger shiftLeft(int); method @NonNull public java.math.BigInteger shiftRight(int); + method public short shortValueExact(); method public int signum(); method @NonNull public java.math.BigInteger subtract(@NonNull java.math.BigInteger); method public boolean testBit(int); diff --git a/non-updatable-api/module-lib-current.txt b/non-updatable-api/module-lib-current.txt index 35b483b9fb84..617a83f05791 100644 --- a/non-updatable-api/module-lib-current.txt +++ b/non-updatable-api/module-lib-current.txt @@ -7,6 +7,7 @@ package android.app { public class NotificationManager { method public boolean hasEnabledNotificationListener(@NonNull String, @NonNull android.os.UserHandle); + field public static final String ACTION_NOTIFICATION_LISTENER_ENABLED_CHANGED = "android.app.action.NOTIFICATION_LISTENER_ENABLED_CHANGED"; } } diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt index cf792b6abbd2..dbf9e9fb4ae5 100644 --- a/non-updatable-api/system-current.txt +++ b/non-updatable-api/system-current.txt @@ -4136,7 +4136,8 @@ package android.media { public class AudioManager { method @Deprecated public int abandonAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, android.media.AudioAttributes); - method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDeviceForStrategyChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener) throws java.lang.SecurityException; + method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDeviceForStrategyChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener) throws java.lang.SecurityException; + method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void addOnPreferredDevicesForStrategyChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.OnPreferredDevicesForStrategyChangedListener) throws java.lang.SecurityException; method public void clearAudioServerStateCallback(); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int dispatchAudioFocusChange(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy); method @IntRange(from=0) public long getAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo); @@ -4148,13 +4149,15 @@ package android.media { method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMinVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.AudioDeviceAttributes getPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy); + method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAttributes> getPreferredDevicesForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int[] getSupportedSystemUsages(); method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); method public boolean isAudioServerRunning(); method public boolean isHdmiSystemAudioSupported(); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int registerAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy); method public void registerVolumeGroupCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.VolumeGroupCallback); - method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDeviceForStrategyChangedListener(@NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener); + method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDeviceForStrategyChangedListener(@NonNull android.media.AudioManager.OnPreferredDeviceForStrategyChangedListener); + method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void removeOnPreferredDevicesForStrategyChangedListener(@NonNull android.media.AudioManager.OnPreferredDevicesForStrategyChangedListener); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean removePreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int) throws java.lang.IllegalArgumentException; method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.MODIFY_AUDIO_ROUTING}) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int, android.media.audiopolicy.AudioPolicy) throws java.lang.IllegalArgumentException; @@ -4164,6 +4167,7 @@ package android.media { method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes, int); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull android.media.AudioDeviceAttributes); + method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDevicesForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull java.util.List<android.media.AudioDeviceAttributes>); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setSupportedSystemUsages(@NonNull int[]); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setVolumeIndexForAttributes(@NonNull android.media.AudioAttributes, int, int); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy); @@ -4187,8 +4191,12 @@ package android.media { method public void onAudioServerUp(); } - public static interface AudioManager.OnPreferredDeviceForStrategyChangedListener { - method public void onPreferredDeviceForStrategyChanged(@NonNull android.media.audiopolicy.AudioProductStrategy, @Nullable android.media.AudioDeviceAttributes); + @Deprecated public static interface AudioManager.OnPreferredDeviceForStrategyChangedListener { + method @Deprecated public void onPreferredDeviceForStrategyChanged(@NonNull android.media.audiopolicy.AudioProductStrategy, @Nullable android.media.AudioDeviceAttributes); + } + + public static interface AudioManager.OnPreferredDevicesForStrategyChangedListener { + method public void onPreferredDevicesForStrategyChanged(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull java.util.List<android.media.AudioDeviceAttributes>); } public abstract static class AudioManager.VolumeGroupCallback { diff --git a/packages/CarSystemUI/proguard.flags b/packages/CarSystemUI/proguard.flags index 66cbf2650429..516e70f56158 100644 --- a/packages/CarSystemUI/proguard.flags +++ b/packages/CarSystemUI/proguard.flags @@ -1,4 +1,6 @@ -keep class com.android.systemui.CarSystemUIFactory -keep class com.android.car.notification.headsup.animationhelper.** +-keep class com.android.systemui.CarGlobalRootComponent { *; } + -include ../SystemUI/proguard.flags diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java b/packages/CarSystemUI/src/com/android/systemui/CarGlobalRootComponent.java index ece3bee000f9..fde0b1a97e46 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarGlobalRootComponent.java @@ -18,9 +18,9 @@ package com.android.systemui; import com.android.systemui.dagger.DependencyBinder; import com.android.systemui.dagger.DependencyProvider; +import com.android.systemui.dagger.GlobalRootComponent; import com.android.systemui.dagger.SystemServicesModule; import com.android.systemui.dagger.SystemUIModule; -import com.android.systemui.dagger.SystemUIRootComponent; import com.android.systemui.onehanded.dagger.OneHandedModule; import com.android.systemui.pip.phone.dagger.PipModule; @@ -28,6 +28,7 @@ import javax.inject.Singleton; import dagger.Component; +/** Car subclass for GlobalRootComponent. */ @Singleton @Component( modules = { @@ -41,12 +42,15 @@ import dagger.Component; CarSystemUIModule.class, CarSystemUIBinder.class }) -public interface CarSystemUIRootComponent extends SystemUIRootComponent { +public interface CarGlobalRootComponent extends GlobalRootComponent { /** - * Builder for a CarSystemUIRootComponent. + * Builder for a CarGlobalRootComponent. */ @Component.Builder - interface Builder extends SystemUIRootComponent.Builder { - CarSystemUIRootComponent build(); + interface Builder extends GlobalRootComponent.Builder { + CarGlobalRootComponent build(); } + + @Override + CarSysUIComponent.Builder getSysUIComponent(); } diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java b/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java new file mode 100644 index 000000000000..d19f368f22b6 --- /dev/null +++ b/packages/CarSystemUI/src/com/android/systemui/CarSysUIComponent.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2019 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; + +import com.android.systemui.dagger.SysUIComponent; +import com.android.systemui.dagger.SysUISingleton; + +import dagger.Subcomponent; + +/** + * Dagger Subcomponent for Core SysUI. + */ +@SysUISingleton +@Subcomponent(modules = {}) +public interface CarSysUIComponent extends SysUIComponent { + + /** + * Builder for a CarSysUIComponent. + */ + @Subcomponent.Builder + interface Builder extends SysUIComponent.Builder { + CarSysUIComponent build(); + } +} diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java index 03ea9418415d..a65edc5477df 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java @@ -19,7 +19,7 @@ package com.android.systemui; import android.content.Context; import android.content.res.Resources; -import com.android.systemui.dagger.SystemUIRootComponent; +import com.android.systemui.dagger.GlobalRootComponent; import java.util.HashSet; import java.util.Set; @@ -30,8 +30,8 @@ import java.util.Set; public class CarSystemUIFactory extends SystemUIFactory { @Override - protected SystemUIRootComponent buildSystemUIRootComponent(Context context) { - return DaggerCarSystemUIRootComponent.builder() + protected GlobalRootComponent buildGlobalRootComponent(Context context) { + return DaggerCarGlobalRootComponent.builder() .context(context) .build(); } diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java index f4e704ea373e..2a96e0925428 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java @@ -32,9 +32,10 @@ import com.android.systemui.car.keyguard.CarKeyguardViewController; import com.android.systemui.car.statusbar.DozeServiceHost; import com.android.systemui.car.statusbar.DummyNotificationShadeWindowController; import com.android.systemui.car.volume.CarVolumeDialogComponent; -import com.android.systemui.dagger.SystemUIRootComponent; +import com.android.systemui.dagger.GlobalRootComponent; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.demomode.DemoModeController; import com.android.systemui.dock.DockManager; import com.android.systemui.dock.DockManagerImpl; import com.android.systemui.doze.DozeHost; @@ -79,8 +80,15 @@ import dagger.Binds; import dagger.Module; import dagger.Provides; -@Module(includes = {DividerModule.class, QSModule.class}) -public abstract class CarSystemUIModule { +@Module( + includes = { + DividerModule.class, + QSModule.class + }, + subcomponents = { + CarSysUIComponent.class + }) +abstract class CarSystemUIModule { @Singleton @Provides @@ -165,10 +173,11 @@ public abstract class CarSystemUIModule { @Singleton static BatteryController provideBatteryController(Context context, EnhancedEstimates enhancedEstimates, PowerManager powerManager, - BroadcastDispatcher broadcastDispatcher, @Main Handler mainHandler, + BroadcastDispatcher broadcastDispatcher, DemoModeController demoModeController, + @Main Handler mainHandler, @Background Handler bgHandler) { BatteryController bC = new BatteryControllerImpl(context, enhancedEstimates, powerManager, - broadcastDispatcher, mainHandler, bgHandler); + broadcastDispatcher, demoModeController, mainHandler, bgHandler); bC.init(); return bC; } @@ -188,8 +197,8 @@ public abstract class CarSystemUIModule { abstract ShadeController provideShadeController(ShadeControllerImpl shadeController); @Binds - abstract SystemUIRootComponent bindSystemUIRootComponent( - CarSystemUIRootComponent systemUIRootComponent); + abstract GlobalRootComponent bindGlobalRootComponent( + CarGlobalRootComponent globalRootComponent); @Binds abstract VolumeDialogComponent bindVolumeDialogComponent( diff --git a/packages/CarSystemUI/src/com/android/systemui/car/volume/CarVolumeDialogComponent.java b/packages/CarSystemUI/src/com/android/systemui/car/volume/CarVolumeDialogComponent.java index 98d24b1fc0e4..d45395744e91 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/volume/CarVolumeDialogComponent.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/volume/CarVolumeDialogComponent.java @@ -19,6 +19,7 @@ package com.android.systemui.car.volume; import android.content.Context; import com.android.systemui.car.CarServiceProvider; +import com.android.systemui.demomode.DemoModeController; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.plugins.VolumeDialog; import com.android.systemui.volume.VolumeDialogComponent; @@ -38,8 +39,9 @@ public class CarVolumeDialogComponent extends VolumeDialogComponent { @Inject public CarVolumeDialogComponent(Context context, KeyguardViewMediator keyguardViewMediator, VolumeDialogControllerImpl volumeDialogController, + DemoModeController demoModeController, CarServiceProvider carServiceProvider) { - super(context, keyguardViewMediator, volumeDialogController); + super(context, keyguardViewMediator, volumeDialogController, demoModeController); mCarVolumeDialog.setCarServiceProvider(carServiceProvider); } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java index 4b4861a01898..59d8acb82196 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java @@ -298,18 +298,12 @@ public class BluetoothEventManager { CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device); if (cachedDevice == null) { cachedDevice = mDeviceManager.addDevice(device); - Log.d(TAG, "DeviceFoundHandler created new CachedBluetoothDevice: " - + cachedDevice); + Log.d(TAG, "DeviceFoundHandler created new CachedBluetoothDevice"); } else if (cachedDevice.getBondState() == BluetoothDevice.BOND_BONDED && !cachedDevice.getDevice().isConnected()) { // Dispatch device add callback to show bonded but // not connected devices in discovery mode dispatchDeviceAdded(cachedDevice); - Log.d(TAG, "DeviceFoundHandler found bonded and not connected device:" - + cachedDevice); - } else { - Log.d(TAG, "DeviceFoundHandler found existing CachedBluetoothDevice:" - + cachedDevice); } cachedDevice.setRssi(rssi); cachedDevice.setJustDiscovered(true); diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index 287f80472478..4c80b91f300d 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -151,8 +151,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> void onProfileStateChanged(LocalBluetoothProfile profile, int newProfileState) { if (BluetoothUtils.D) { - Log.d(TAG, "onProfileStateChanged: profile " + profile + ", device=" + mDevice - + ", newProfileState " + newProfileState); + Log.d(TAG, "onProfileStateChanged: profile " + profile + ", device " + + mDevice.getAlias() + ", newProfileState " + newProfileState); } if (mLocalAdapter.getState() == BluetoothAdapter.STATE_TURNING_OFF) { @@ -290,9 +290,6 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> } public void setHiSyncId(long id) { - if (BluetoothUtils.D) { - Log.d(TAG, "setHiSyncId: mDevice " + mDevice + ", id " + id); - } mHiSyncId = id; } @@ -638,7 +635,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> } if (BluetoothUtils.D) { - Log.e(TAG, "updating profiles for " + mDevice.getAlias() + ", " + mDevice); + Log.d(TAG, "updating profiles for " + mDevice.getAlias()); BluetoothClass bluetoothClass = mDevice.getBluetoothClass(); if (bluetoothClass != null) Log.v(TAG, "Class: " + bluetoothClass.toString()); diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java index 4eea8ad92e61..f1a3fee0ea9f 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java @@ -165,6 +165,7 @@ public class SecureSettings { Settings.Secure.AWARE_TAP_PAUSE_TOUCH_COUNT, Settings.Secure.PEOPLE_STRIP, Settings.Secure.MEDIA_CONTROLS_RESUME, + Settings.Secure.MEDIA_CONTROLS_RESUME_BLOCKED, Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, Settings.Secure.ACCESSIBILITY_MAGNIFICATION_CAPABILITY, diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java index c68ddbdcb5ad..04916e2c0e2b 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java @@ -244,6 +244,8 @@ public class SecureSettingsValidators { VALIDATORS.put(Secure.TAP_GESTURE, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.PEOPLE_STRIP, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.MEDIA_CONTROLS_RESUME, BOOLEAN_VALIDATOR); + VALIDATORS.put(Secure.MEDIA_CONTROLS_RESUME_BLOCKED, + COLON_SEPARATED_PACKAGE_LIST_VALIDATOR); VALIDATORS.put(Secure.ACCESSIBILITY_MAGNIFICATION_MODE, new InclusiveIntegerRangeValidator( Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN, diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java index d2112a0ce759..883f4de1149c 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationMenuRowPlugin.java @@ -75,11 +75,6 @@ public interface NotificationMenuRowPlugin extends Plugin { public MenuItem getLongpressMenuItem(Context context); /** - * @return the {@link MenuItem} to display when app ops icons are pressed. - */ - public MenuItem getAppOpsMenuItem(Context context); - - /** * @return the {@link MenuItem} to display when feedback icon is pressed. */ public MenuItem getFeedbackMenuItem(Context context); diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags index 14097b12e730..92e7d88868da 100644 --- a/packages/SystemUI/proguard.flags +++ b/packages/SystemUI/proguard.flags @@ -1,9 +1,9 @@ --keep class com.android.systemui.statusbar.policy.KeyButtonView { +-keep class com.android.systemui.navigationbar.buttons.KeyButtonView { public float getDrawingAlpha(); public void setDrawingAlpha(float); } --keep class com.android.systemui.statusbar.policy.KeyButtonRipple { +-keep class com.android.systemui.navigationbar.buttons.KeyButtonRipple { public float getGlowAlpha(); public float getGlowScale(); public void setGlowAlpha(float); @@ -41,4 +41,6 @@ public <init>(android.content.Context); } --keep class com.android.wm.shell.*
\ No newline at end of file +-keep class com.android.wm.shell.* + +-keep class com.android.systemui.dagger.GlobalRootComponent { *; }
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/back.xml b/packages/SystemUI/res/layout/back.xml index 4e8726b3a634..046aecda44b3 100644 --- a/packages/SystemUI/res/layout/back.xml +++ b/packages/SystemUI/res/layout/back.xml @@ -14,7 +14,7 @@ limitations under the License. --> -<com.android.systemui.statusbar.policy.KeyButtonView +<com.android.systemui.navigationbar.buttons.KeyButtonView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:systemui="http://schemas.android.com/apk/res-auto" android:id="@+id/back" diff --git a/packages/SystemUI/res/layout/contextual.xml b/packages/SystemUI/res/layout/contextual.xml index 90a776884699..2cd7926b6e46 100644 --- a/packages/SystemUI/res/layout/contextual.xml +++ b/packages/SystemUI/res/layout/contextual.xml @@ -24,7 +24,7 @@ android:clipChildren="false" android:clipToPadding="false" > - <com.android.systemui.statusbar.policy.KeyButtonView + <com.android.systemui.navigationbar.buttons.KeyButtonView android:id="@+id/menu" android:layout_height="match_parent" android:layout_width="match_parent" @@ -47,7 +47,7 @@ android:layout_height="match_parent" android:visibility="invisible" /> - <com.android.systemui.statusbar.policy.KeyButtonView + <com.android.systemui.navigationbar.buttons.KeyButtonView android:id="@+id/accessibility_button" android:layout_width="match_parent" android:layout_height="match_parent" diff --git a/packages/SystemUI/res/layout/custom_key.xml b/packages/SystemUI/res/layout/custom_key.xml index 0b5cb7267610..dc65777542e2 100644 --- a/packages/SystemUI/res/layout/custom_key.xml +++ b/packages/SystemUI/res/layout/custom_key.xml @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. --> -<com.android.systemui.statusbar.policy.KeyButtonView +<com.android.systemui.navigationbar.buttons.KeyButtonView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:systemui="http://schemas.android.com/apk/res-auto" android:layout_width="@dimen/navigation_side_padding" diff --git a/packages/SystemUI/res/layout/home.xml b/packages/SystemUI/res/layout/home.xml index 95863272b9bf..84eed6a233f8 100644 --- a/packages/SystemUI/res/layout/home.xml +++ b/packages/SystemUI/res/layout/home.xml @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. --> -<com.android.systemui.statusbar.policy.KeyButtonView +<com.android.systemui.navigationbar.buttons.KeyButtonView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:systemui="http://schemas.android.com/apk/res-auto" android:id="@+id/home" diff --git a/packages/SystemUI/res/layout/home_handle.xml b/packages/SystemUI/res/layout/home_handle.xml index 54a0b9fba39c..c9d3f987902c 100644 --- a/packages/SystemUI/res/layout/home_handle.xml +++ b/packages/SystemUI/res/layout/home_handle.xml @@ -15,7 +15,7 @@ ~ limitations under the License. --> -<com.android.systemui.statusbar.phone.NavigationHandle +<com.android.systemui.navigationbar.gestural.NavigationHandle xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/home_handle" android:layout_width="@dimen/navigation_home_handle_width" diff --git a/packages/SystemUI/res/layout/ime_switcher.xml b/packages/SystemUI/res/layout/ime_switcher.xml index 7710b25d6e4c..a2c8308b7f70 100644 --- a/packages/SystemUI/res/layout/ime_switcher.xml +++ b/packages/SystemUI/res/layout/ime_switcher.xml @@ -15,7 +15,7 @@ ~ limitations under the License --> -<com.android.systemui.statusbar.policy.KeyButtonView +<com.android.systemui.navigationbar.buttons.KeyButtonView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/ime_switcher" android:layout_width="@dimen/navigation_key_width" diff --git a/packages/SystemUI/res/layout/menu_ime.xml b/packages/SystemUI/res/layout/menu_ime.xml index df717f601763..0bb622bb9c4f 100644 --- a/packages/SystemUI/res/layout/menu_ime.xml +++ b/packages/SystemUI/res/layout/menu_ime.xml @@ -25,7 +25,7 @@ are placed inside a view that has a size controlled by weight. Ensure weight is large enough to support icon size. Use layout_width=navigation_side_padding like other navbar buttons. --> - <com.android.systemui.statusbar.policy.KeyButtonView + <com.android.systemui.navigationbar.buttons.KeyButtonView android:id="@+id/menu" android:layout_width="match_parent" android:layout_height="match_parent" @@ -43,7 +43,7 @@ android:paddingStart="0dp" android:paddingEnd="0dp" /> - <com.android.systemui.statusbar.policy.KeyButtonView + <com.android.systemui.navigationbar.buttons.KeyButtonView android:id="@+id/rotate_suggestion" android:layout_width="match_parent" android:layout_height="match_parent" @@ -51,7 +51,7 @@ android:scaleType="centerInside" android:contentDescription="@string/accessibility_rotate_button" /> - <com.android.systemui.statusbar.policy.KeyButtonView + <com.android.systemui.navigationbar.buttons.KeyButtonView android:id="@+id/accessibility_button" android:layout_width="match_parent" android:layout_height="match_parent" diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml index ba6b6956f187..23f36a98ed3e 100644 --- a/packages/SystemUI/res/layout/navigation_bar.xml +++ b/packages/SystemUI/res/layout/navigation_bar.xml @@ -17,9 +17,10 @@ */ --> -<com.android.systemui.statusbar.phone.NavigationBarView +<com.android.systemui.navigationbar.NavigationBarView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:systemui="http://schemas.android.com/apk/res-auto" + android:id="@+id/navigation_bar_view" android:layout_height="match_parent" android:layout_width="match_parent" android:background="@drawable/system_bar_background"> @@ -39,9 +40,9 @@ android:rotation="180" android:visibility="gone"/> - <com.android.systemui.statusbar.phone.NavigationBarInflaterView + <com.android.systemui.navigationbar.NavigationBarInflaterView android:id="@+id/navigation_inflater" android:layout_width="match_parent" android:layout_height="match_parent" /> -</com.android.systemui.statusbar.phone.NavigationBarView> +</com.android.systemui.navigationbar.NavigationBarView> diff --git a/packages/SystemUI/res/layout/navigation_bar_window.xml b/packages/SystemUI/res/layout/navigation_bar_window.xml index f98cbd8d10fa..b2473cd82998 100644 --- a/packages/SystemUI/res/layout/navigation_bar_window.xml +++ b/packages/SystemUI/res/layout/navigation_bar_window.xml @@ -16,7 +16,7 @@ ** limitations under the License. */ --> -<com.android.systemui.statusbar.phone.NavigationBarFrame +<com.android.systemui.navigationbar.NavigationBarFrame xmlns:android="http://schemas.android.com/apk/res/android" xmlns:systemui="http://schemas.android.com/apk/res-auto" android:id="@+id/navigation_bar_frame" @@ -24,4 +24,4 @@ android:layout_height="match_parent" android:layout_width="match_parent"> -</com.android.systemui.statusbar.phone.NavigationBarFrame> +</com.android.systemui.navigationbar.NavigationBarFrame> diff --git a/packages/SystemUI/res/layout/navigation_layout.xml b/packages/SystemUI/res/layout/navigation_layout.xml index db1c79d24c54..0e576fbe2245 100644 --- a/packages/SystemUI/res/layout/navigation_layout.xml +++ b/packages/SystemUI/res/layout/navigation_layout.xml @@ -25,7 +25,7 @@ android:paddingEnd="@dimen/nav_content_padding" android:id="@+id/horizontal"> - <com.android.systemui.statusbar.phone.NearestTouchFrame + <com.android.systemui.navigationbar.buttons.NearestTouchFrame android:id="@+id/nav_buttons" android:layout_width="match_parent" android:layout_height="match_parent" @@ -50,6 +50,6 @@ android:clipToPadding="false" android:clipChildren="false" /> - </com.android.systemui.statusbar.phone.NearestTouchFrame> + </com.android.systemui.navigationbar.buttons.NearestTouchFrame> </FrameLayout> diff --git a/packages/SystemUI/res/layout/navigation_layout_vertical.xml b/packages/SystemUI/res/layout/navigation_layout_vertical.xml index 285c5c4e0a01..4b6770042632 100644 --- a/packages/SystemUI/res/layout/navigation_layout_vertical.xml +++ b/packages/SystemUI/res/layout/navigation_layout_vertical.xml @@ -25,14 +25,14 @@ android:paddingBottom="@dimen/nav_content_padding" android:id="@+id/vertical"> - <com.android.systemui.statusbar.phone.NearestTouchFrame + <com.android.systemui.navigationbar.buttons.NearestTouchFrame android:id="@+id/nav_buttons" android:layout_width="match_parent" android:layout_height="match_parent" android:clipChildren="false" android:clipToPadding="false"> - <com.android.systemui.statusbar.phone.ReverseLinearLayout + <com.android.systemui.navigationbar.buttons.ReverseLinearLayout android:id="@+id/ends_group" android:layout_width="match_parent" android:layout_height="match_parent" @@ -40,7 +40,7 @@ android:clipToPadding="false" android:clipChildren="false" /> - <com.android.systemui.statusbar.phone.ReverseLinearLayout + <com.android.systemui.navigationbar.buttons.ReverseLinearLayout android:id="@+id/center_group" android:layout_width="match_parent" android:layout_height="match_parent" @@ -49,6 +49,6 @@ android:clipToPadding="false" android:clipChildren="false" /> - </com.android.systemui.statusbar.phone.NearestTouchFrame> + </com.android.systemui.navigationbar.buttons.NearestTouchFrame> </FrameLayout> diff --git a/packages/SystemUI/res/layout/recent_apps.xml b/packages/SystemUI/res/layout/recent_apps.xml index 870bcf7547a7..e2b1374b6a78 100644 --- a/packages/SystemUI/res/layout/recent_apps.xml +++ b/packages/SystemUI/res/layout/recent_apps.xml @@ -14,7 +14,7 @@ limitations under the License. --> -<com.android.systemui.statusbar.policy.KeyButtonView +<com.android.systemui.navigationbar.buttons.KeyButtonView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:systemui="http://schemas.android.com/apk/res-auto" android:id="@+id/recent_apps" diff --git a/packages/SystemUI/res/layout/rotate_suggestion.xml b/packages/SystemUI/res/layout/rotate_suggestion.xml index d7f67db0390c..194d2e063e97 100644 --- a/packages/SystemUI/res/layout/rotate_suggestion.xml +++ b/packages/SystemUI/res/layout/rotate_suggestion.xml @@ -15,7 +15,7 @@ ~ limitations under the License --> -<com.android.systemui.statusbar.policy.KeyButtonView +<com.android.systemui.navigationbar.buttons.KeyButtonView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/rotate_suggestion" android:layout_width="match_parent" diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 17ba7c99dc0c..ce1ca5ad1723 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -565,15 +565,9 @@ <!-- If the config font scale is >= this value, potentially adjust the number of columns--> <item name="controls_max_columns_adjust_above_font_scale" translatable="false" format="float" type="dimen">1.25</item> - <!-- One handed mode default offset % of display size --> - <fraction name="config_one_handed_offset">50%</fraction> - <!-- Allow one handed to enable round corner --> <bool name="config_one_handed_enable_round_corner">true</bool> - <!-- Animation duration for translating of one handed when trigger / dismiss. --> - <integer name="config_one_handed_translate_animation_duration">150</integer> - <!-- Show a separate icon for low and high volume on the volume dialog --> <bool name="config_showLowMediaVolumeIcon">false</bool> </resources> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java index d6fabd63420d..6f19613be28f 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java @@ -36,8 +36,8 @@ import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.Dependency; import com.android.systemui.R; -import com.android.systemui.statusbar.NavigationBarController; -import com.android.systemui.statusbar.phone.NavigationBarView; +import com.android.systemui.navigationbar.NavigationBarController; +import com.android.systemui.navigationbar.NavigationBarView; import com.android.systemui.util.InjectionInflationController; public class KeyguardDisplayManager { @@ -54,9 +54,6 @@ public class KeyguardDisplayManager { private final SparseArray<Presentation> mPresentations = new SparseArray<>(); - private final NavigationBarController mNavBarController = - Dependency.get(NavigationBarController.class); - private final DisplayManager.DisplayListener mDisplayListener = new DisplayManager.DisplayListener() { @@ -227,7 +224,8 @@ public class KeyguardDisplayManager { // Leave this task to {@link StatusBarKeyguardViewManager} if (displayId == DEFAULT_DISPLAY) return; - NavigationBarView navBarView = mNavBarController.getNavigationBarView(displayId); + NavigationBarView navBarView = Dependency.get(NavigationBarController.class) + .getNavigationBarView(displayId); // We may not have nav bar on a display. if (navBarView == null) return; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index 1db2e32b8cdb..5f00a591860e 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -256,7 +256,7 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe mUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class); mSpringAnimation = new SpringAnimation(this, DynamicAnimation.Y); mInjectionInflationController = new InjectionInflationController( - SystemUIFactory.getInstance().getRootComponent()); + SystemUIFactory.getInstance().getRootComponent().createViewInstanceCreatorFactory()); mViewConfiguration = ViewConfiguration.get(context); mKeyguardStateController = Dependency.get(KeyguardStateController.class); mSecondaryLockScreenController = new AdminSecondaryLockScreenController(context, this, diff --git a/packages/SystemUI/src/com/android/systemui/DemoMode.java b/packages/SystemUI/src/com/android/systemui/DemoMode.java deleted file mode 100644 index 5c3971571b87..000000000000 --- a/packages/SystemUI/src/com/android/systemui/DemoMode.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2013 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; - -import android.os.Bundle; - -public interface DemoMode { - - public static final String DEMO_MODE_ALLOWED = "sysui_demo_allowed"; - - void dispatchDemoCommand(String command, Bundle args); - - public static final String ACTION_DEMO = "com.android.systemui.demo"; - - public static final String EXTRA_COMMAND = "command"; - - public static final String COMMAND_ENTER = "enter"; - public static final String COMMAND_EXIT = "exit"; - public static final String COMMAND_CLOCK = "clock"; - public static final String COMMAND_BATTERY = "battery"; - public static final String COMMAND_NETWORK = "network"; - public static final String COMMAND_BARS = "bars"; - public static final String COMMAND_STATUS = "status"; - public static final String COMMAND_NOTIFICATIONS = "notifications"; - public static final String COMMAND_VOLUME = "volume"; - public static final String COMMAND_OPERATOR = "operator"; -} diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index 58f8c07ad7c9..10f2069087d5 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -64,7 +64,7 @@ import com.android.systemui.shared.system.DevicePolicyManagerWrapper; import com.android.systemui.shared.system.PackageManagerWrapper; import com.android.systemui.stackdivider.Divider; import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.NavigationBarController; +import com.android.systemui.navigationbar.NavigationBarController; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationMediaManager; @@ -85,7 +85,7 @@ import com.android.systemui.statusbar.phone.KeyguardDismissUtil; import com.android.systemui.statusbar.phone.LightBarController; import com.android.systemui.statusbar.phone.LockscreenGestureLogger; import com.android.systemui.statusbar.phone.ManagedProfileController; -import com.android.systemui.statusbar.phone.NavigationModeController; +import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.NotificationShadeWindowController; diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java index 2deeb1230f09..5f8815665d88 100644 --- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java +++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java @@ -39,21 +39,15 @@ import javax.inject.Singleton; */ @Singleton public class ForegroundServiceController { - public static final int[] APP_OPS = new int[] {AppOpsManager.OP_CAMERA, - AppOpsManager.OP_SYSTEM_ALERT_WINDOW, - AppOpsManager.OP_RECORD_AUDIO, - AppOpsManager.OP_COARSE_LOCATION, - AppOpsManager.OP_FINE_LOCATION}; + public static final int[] APP_OPS = new int[] {AppOpsManager.OP_SYSTEM_ALERT_WINDOW}; private final SparseArray<ForegroundServicesUserState> mUserServices = new SparseArray<>(); private final Object mMutex = new Object(); - private final NotificationEntryManager mEntryManager; private final Handler mMainHandler; @Inject - public ForegroundServiceController(NotificationEntryManager entryManager, - AppOpsController appOpsController, @Main Handler mainHandler) { - mEntryManager = entryManager; + public ForegroundServiceController(AppOpsController appOpsController, + @Main Handler mainHandler) { mMainHandler = mainHandler; appOpsController.addCallback(APP_OPS, (code, uid, packageName, active) -> { mMainHandler.post(() -> { @@ -87,19 +81,6 @@ public class ForegroundServiceController { } /** - * Returns the keys for notifications from this package using the standard template, - * if they exist. - */ - @Nullable - public ArraySet<String> getStandardLayoutKeys(int userId, String pkg) { - synchronized (mMutex) { - final ForegroundServicesUserState services = mUserServices.get(userId); - if (services == null) return null; - return services.getStandardLayoutKeys(pkg); - } - } - - /** * Gets active app ops for this user and package */ @Nullable @@ -140,31 +121,6 @@ public class ForegroundServiceController { userServices.removeOp(packageName, appOpCode); } } - - // TODO: (b/145659174) remove when moving to NewNotifPipeline. Replaced by - // AppOpsCoordinator - // Update appOps if there are associated pending or visible notifications - final Set<String> notificationKeys = getStandardLayoutKeys(userId, packageName); - if (notificationKeys != null) { - boolean changed = false; - for (String key : notificationKeys) { - final NotificationEntry entry = mEntryManager.getPendingOrActiveNotif(key); - if (entry != null - && uid == entry.getSbn().getUid() - && packageName.equals(entry.getSbn().getPackageName())) { - synchronized (entry.mActiveAppOps) { - if (active) { - changed |= entry.mActiveAppOps.add(appOpCode); - } else { - changed |= entry.mActiveAppOps.remove(appOpCode); - } - } - } - } - if (changed) { - mEntryManager.updateNotifications("appOpChanged pkg=" + packageName); - } - } } /** diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java index bb445832da93..1515272569d6 100644 --- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java +++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java @@ -172,24 +172,8 @@ public class ForegroundServiceNotificationListener { sbn.getPackageName(), sbn.getKey()); } } - tagAppOps(entry); return true; }, true /* create if not found */); } - - // TODO: (b/145659174) remove when moving to NewNotifPipeline. Replaced by - // AppOpsCoordinator - private void tagAppOps(NotificationEntry entry) { - final StatusBarNotification sbn = entry.getSbn(); - ArraySet<Integer> activeOps = mForegroundServiceController.getAppOps( - sbn.getUserId(), - sbn.getPackageName()); - synchronized (entry.mActiveAppOps) { - entry.mActiveAppOps.clear(); - if (activeOps != null) { - entry.mActiveAppOps.addAll(activeOps); - } - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java index 449ed8c3bcdb..2365f128532e 100644 --- a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java @@ -16,6 +16,7 @@ package com.android.systemui; import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; +import android.annotation.Nullable; import android.app.Activity; import android.app.AlertDialog; import android.app.slice.SliceManager; @@ -29,6 +30,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.net.Uri; import android.os.Bundle; import android.text.BidiFormatter; +import android.util.EventLog; import android.util.Log; import android.widget.CheckBox; import android.widget.TextView; @@ -50,10 +52,17 @@ public class SlicePermissionActivity extends Activity implements OnClickListener mUri = getIntent().getParcelableExtra(SliceProvider.EXTRA_BIND_URI); mCallingPkg = getIntent().getStringExtra(SliceProvider.EXTRA_PKG); - mProviderPkg = getIntent().getStringExtra(SliceProvider.EXTRA_PROVIDER_PKG); + if (mUri == null) { + Log.e(TAG, SliceProvider.EXTRA_BIND_URI + " wasn't provided"); + finish(); + return; + } try { PackageManager pm = getPackageManager(); + mProviderPkg = pm.resolveContentProvider(mUri.getAuthority(), + PackageManager.GET_META_DATA).applicationInfo.packageName; + verifyCallingPkg(); CharSequence app1 = BidiFormatter.getInstance().unicodeWrap(pm.getApplicationInfo( mCallingPkg, 0).loadSafeLabel(pm, PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX, PackageItemInfo.SAFE_LABEL_FLAG_TRIM @@ -97,4 +106,29 @@ public class SlicePermissionActivity extends Activity implements OnClickListener public void onDismiss(DialogInterface dialog) { finish(); } + + private void verifyCallingPkg() { + final String providerPkg = getIntent().getStringExtra("provider_pkg"); + if (providerPkg == null || mProviderPkg.equals(providerPkg)) return; + final String callingPkg = getCallingPkg(); + EventLog.writeEvent(0x534e4554, "159145361", getUid(callingPkg), String.format( + "pkg %s (disguised as %s) attempted to request permission to show %s slices in %s", + callingPkg, providerPkg, mProviderPkg, mCallingPkg)); + } + + @Nullable + private String getCallingPkg() { + final Uri referrer = getReferrer(); + if (referrer == null) return null; + return referrer.getHost(); + } + + private int getUid(@Nullable final String pkg) { + if (pkg == null) return -1; + try { + return getPackageManager().getApplicationInfo(pkg, 0).uid; + } catch (NameNotFoundException e) { + } + return -1; + } } diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java index cacbf969e562..627f5592e667 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java @@ -29,6 +29,10 @@ import androidx.annotation.Nullable; import androidx.core.app.AppComponentFactory; import com.android.systemui.dagger.ContextComponentHelper; +import com.android.systemui.dagger.GlobalRootComponent; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import javax.inject.Inject; @@ -81,8 +85,17 @@ public class SystemUIAppComponentFactory extends AppComponentFactory { ((ContextInitializer) contentProvider).setContextAvailableCallback( context -> { SystemUIFactory.createFromConfig(context); - SystemUIFactory.getInstance().getRootComponent().inject( - contentProvider); + GlobalRootComponent rootComponent = + SystemUIFactory.getInstance().getRootComponent(); + try { + Method injectMethod = rootComponent.getClass() + .getMethod("inject", contentProvider.getClass()); + injectMethod.invoke(rootComponent, contentProvider); + } catch (NoSuchMethodException + | IllegalAccessException + | InvocationTargetException e) { + // no-op + } } ); } diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java index c84701c9512e..4f78f65f0121 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java @@ -32,7 +32,7 @@ import android.util.Log; import android.util.TimingsTraceLog; import com.android.systemui.dagger.ContextComponentHelper; -import com.android.systemui.dagger.SystemUIRootComponent; +import com.android.systemui.dagger.GlobalRootComponent; import com.android.systemui.dump.DumpManager; import com.android.systemui.util.NotificationChannels; @@ -57,7 +57,7 @@ public class SystemUIApplication extends Application implements private SystemUI[] mServices; private boolean mServicesStarted; private SystemUIAppComponentFactory.ContextAvailableCallback mContextAvailableCallback; - private SystemUIRootComponent mRootComponent; + private GlobalRootComponent mRootComponent; public SystemUIApplication() { super(); diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java index 1a15c0aae8c1..e34a653f4d2f 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java @@ -28,8 +28,11 @@ import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.bubbles.BubbleController; -import com.android.systemui.dagger.DaggerSystemUIRootComponent; -import com.android.systemui.dagger.SystemUIRootComponent; +import com.android.systemui.dagger.DaggerGlobalRootComponent; +import com.android.systemui.dagger.GlobalRootComponent; +import com.android.systemui.dagger.SysUIComponent; +import com.android.systemui.dagger.WMComponent; +import com.android.systemui.demomode.DemoModeController; import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -53,7 +56,9 @@ public class SystemUIFactory { private static final String TAG = "SystemUIFactory"; static SystemUIFactory mFactory; - private SystemUIRootComponent mRootComponent; + private GlobalRootComponent mRootComponent; + private WMComponent mWMComponent; + private SysUIComponent mSysUIComponent; public static <T extends SystemUIFactory> T getInstance() { return (T) mFactory; @@ -88,7 +93,10 @@ public class SystemUIFactory { public SystemUIFactory() {} private void init(Context context) { - mRootComponent = buildSystemUIRootComponent(context); + mRootComponent = buildGlobalRootComponent(context); + mWMComponent = mRootComponent.getWMComponentBuilder().build(); + // TODO: use WMComponent to pass APIs into the SysUIComponent. + mSysUIComponent = mRootComponent.getSysUIComponent().build(); // Every other part of our codebase currently relies on Dependency, so we // really need to ensure the Dependency gets initialized early on. @@ -96,13 +104,13 @@ public class SystemUIFactory { dependency.start(); } - protected SystemUIRootComponent buildSystemUIRootComponent(Context context) { - return DaggerSystemUIRootComponent.builder() + protected GlobalRootComponent buildGlobalRootComponent(Context context) { + return DaggerGlobalRootComponent.builder() .context(context) .build(); } - public SystemUIRootComponent getRootComponent() { + public GlobalRootComponent getRootComponent() { return mRootComponent; } @@ -144,12 +152,14 @@ public class SystemUIFactory { StatusBar statusBar, NotificationWakeUpCoordinator wakeUpCoordinator, KeyguardBypassController keyguardBypassController, - StatusBarStateController statusBarStateController) { + StatusBarStateController statusBarStateController, + DemoModeController demoModeController) { return new NotificationIconAreaController(context, statusBar, statusBarStateController, wakeUpCoordinator, keyguardBypassController, Dependency.get(NotificationMediaManager.class), Dependency.get(NotificationListener.class), Dependency.get(DozeParameters.class), - Dependency.get(BubbleController.class)); + Dependency.get(BubbleController.class), + demoModeController); } } diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java index 0135e4cddc56..17525798ae08 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java @@ -130,8 +130,6 @@ public class SystemActions extends SystemUI { private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF"; - private Recents mRecents; - private StatusBar mStatusBar; private SystemActionsBroadcastReceiver mReceiver; private Locale mLocale; private AccessibilityManager mA11yManager; @@ -139,8 +137,6 @@ public class SystemActions extends SystemUI { @Inject public SystemActions(Context context) { super(context); - mRecents = Dependency.get(Recents.class); - mStatusBar = Dependency.get(StatusBar.class); mReceiver = new SystemActionsBroadcastReceiver(); mLocale = mContext.getResources().getConfiguration().getLocales().get(0); mA11yManager = (AccessibilityManager) mContext.getSystemService( @@ -317,15 +313,15 @@ public class SystemActions extends SystemUI { } private void handleRecents() { - mRecents.toggleRecentApps(); + Dependency.get(Recents.class).toggleRecentApps(); } private void handleNotifications() { - mStatusBar.animateExpandNotificationsPanel(); + Dependency.get(StatusBar.class).animateExpandNotificationsPanel(); } private void handleQuickSettings() { - mStatusBar.animateExpandSettingsPanel(null); + Dependency.get(StatusBar.class).animateExpandSettingsPanel(null); } private void handlePowerDialog() { diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java index 7ae3e73caa23..2df48fc90a94 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java +++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java @@ -35,7 +35,7 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.Dumpable; import com.android.systemui.dump.DumpManager; import com.android.systemui.shared.system.QuickStepContract; -import com.android.systemui.statusbar.phone.NavigationModeController; +import com.android.systemui.navigationbar.NavigationModeController; import java.io.FileDescriptor; import java.io.PrintWriter; diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleViewController.java b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleViewController.java index 5010f319f8b4..f19e53f03849 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleViewController.java +++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleViewController.java @@ -30,7 +30,7 @@ import android.view.animation.PathInterpolator; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.CornerHandleView; import com.android.systemui.R; -import com.android.systemui.statusbar.phone.NavigationBarTransitions; +import com.android.systemui.navigationbar.NavigationBarTransitions; /** * A class for managing Assistant handle show, hide and animation. diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistModule.java b/packages/SystemUI/src/com/android/systemui/assist/AssistModule.java index 6f5a17dca432..0dc06f2d5e21 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/AssistModule.java +++ b/packages/SystemUI/src/com/android/systemui/assist/AssistModule.java @@ -25,7 +25,7 @@ import androidx.annotation.Nullable; import androidx.slice.Clock; import com.android.internal.app.AssistUtils; -import com.android.systemui.statusbar.NavigationBarController; +import com.android.systemui.navigationbar.NavigationBarController; import java.util.EnumMap; import java.util.Map; diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java b/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java index 05f3617dd1d6..722e3124d871 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java +++ b/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java @@ -41,7 +41,7 @@ import com.android.systemui.assist.AssistHandleViewController; import com.android.systemui.assist.AssistLogger; import com.android.systemui.assist.AssistManager; import com.android.systemui.assist.AssistantSessionEvent; -import com.android.systemui.statusbar.NavigationBarController; +import com.android.systemui.navigationbar.NavigationBarController; import java.util.Locale; diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java b/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java index e5121a8ea35c..ac39ed501811 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java +++ b/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java @@ -33,9 +33,9 @@ import android.view.View; import com.android.settingslib.Utils; import com.android.systemui.Dependency; import com.android.systemui.R; -import com.android.systemui.statusbar.NavigationBarController; -import com.android.systemui.statusbar.phone.NavigationBarFragment; -import com.android.systemui.statusbar.phone.NavigationBarTransitions; +import com.android.systemui.navigationbar.NavigationBarController; +import com.android.systemui.navigationbar.NavigationBar; +import com.android.systemui.navigationbar.NavigationBarTransitions; import java.util.ArrayList; @@ -284,7 +284,7 @@ public class InvocationLightsView extends View return; } - NavigationBarFragment navBar = controller.getDefaultNavigationBarFragment(); + NavigationBar navBar = controller.getDefaultNavigationBar(); if (navBar == null) { return; } @@ -301,7 +301,7 @@ public class InvocationLightsView extends View return; } - NavigationBarFragment navBar = controller.getDefaultNavigationBarFragment(); + NavigationBar navBar = controller.getDefaultNavigationBar(); if (navBar == null) { return; } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index 361ea674cead..ade106fb2223 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -280,7 +280,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, fpm.getSensorProperties(); for (FingerprintSensorProperties props : fingerprintSensorProperties) { if (props.sensorType == FingerprintSensorProperties.TYPE_UDFPS) { - mUdfpsController = new UdfpsController(mContext, mWindowManager); + mUdfpsController = new UdfpsController(mContext); break; } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index 739c2b155444..e3126b89fe78 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -17,21 +17,27 @@ package com.android.systemui.biometrics; import android.annotation.SuppressLint; +import android.content.ContentResolver; import android.content.Context; +import android.content.res.TypedArray; import android.graphics.PixelFormat; import android.graphics.Point; import android.hardware.fingerprint.FingerprintManager; -import android.hardware.fingerprint.IFingerprintService; import android.hardware.fingerprint.IUdfpsOverlayController; import android.os.Handler; import android.os.Looper; -import android.os.RemoteException; +import android.os.PowerManager; +import android.os.UserHandle; +import android.provider.Settings; import android.util.Log; +import android.util.MathUtils; +import android.util.Spline; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.WindowManager; import android.widget.LinearLayout; +import com.android.internal.BrightnessSynchronizer; import com.android.systemui.R; import java.io.FileWriter; @@ -43,17 +49,31 @@ import java.io.IOException; */ class UdfpsController { private static final String TAG = "UdfpsController"; + // Gamma approximation for the sRGB color space. + private static final float DISPLAY_GAMMA = 2.2f; - private final Context mContext; private final FingerprintManager mFingerprintManager; private final WindowManager mWindowManager; + private final ContentResolver mContentResolver; private final Handler mHandler; - - private UdfpsView mView; - private WindowManager.LayoutParams mLayoutParams; - private String mHbmPath; - private String mHbmEnableCommand; - private String mHbmDisableCommand; + private final UdfpsView mView; + private final WindowManager.LayoutParams mLayoutParams; + // Debugfs path to control the high-brightness mode. + private final String mHbmPath; + private final String mHbmEnableCommand; + private final String mHbmDisableCommand; + // Brightness in nits in the high-brightness mode. + private final float mHbmNits; + // A spline mapping from the device's backlight value, normalized to the range [0, 1.0], to a + // brightness in nits. + private final Spline mBacklightToNitsSpline; + // A spline mapping from a value in nits to a backlight value of a hypothetical panel whose + // maximum backlight value corresponds to our panel's high-brightness mode. + // The output is normalized to the range [0, 1.0]. + private Spline mNitsToHbmBacklightSpline; + // Default non-HBM backlight value normalized to the range [0, 1.0]. Used as a fallback when the + // actual brightness value cannot be retrieved. + private final float mDefaultBrightness; private boolean mIsOverlayShowing; public class UdfpsOverlayController extends IUdfpsOverlayController.Stub { @@ -70,22 +90,23 @@ class UdfpsController { @SuppressLint("ClickableViewAccessibility") private final UdfpsView.OnTouchListener mOnTouchListener = (v, event) -> { + UdfpsView view = (UdfpsView) v; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_MOVE: - boolean isValidTouch = mView.isValidTouch(event.getX(), event.getY(), + boolean isValidTouch = view.isValidTouch(event.getX(), event.getY(), event.getPressure()); - if (!mView.isFingerDown() && isValidTouch) { + if (!view.isFingerDown() && isValidTouch) { onFingerDown((int) event.getX(), (int) event.getY(), event.getTouchMinor(), event.getTouchMajor()); - } else if (mView.isFingerDown() && !isValidTouch) { + } else if (view.isFingerDown() && !isValidTouch) { onFingerUp(); } return true; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: - if (mView.isFingerDown()) { + if (view.isFingerDown()) { onFingerUp(); } return true; @@ -95,43 +116,51 @@ class UdfpsController { } }; - UdfpsController(Context context, WindowManager windowManager) { - mContext = context; + UdfpsController(Context context) { mFingerprintManager = context.getSystemService(FingerprintManager.class); - mWindowManager = windowManager; + mWindowManager = context.getSystemService(WindowManager.class); + mContentResolver = context.getContentResolver(); mHandler = new Handler(Looper.getMainLooper()); - start(); - } - - private void start() { - Log.v(TAG, "start"); - - Point displaySize = new Point(); - mWindowManager.getDefaultDisplay().getRealSize(displaySize); - // TODO(b/160025856): move to the "dump" method. - Log.v(TAG, "UdfpsController | display size: " + displaySize.x + "x" - + displaySize.y); - - mLayoutParams = new WindowManager.LayoutParams( - displaySize.x, - displaySize.y, - // TODO(b/152419866): Use the UDFPS window type when it becomes available. - WindowManager.LayoutParams.TYPE_BOOT_PROGRESS, - WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN - | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, - PixelFormat.TRANSLUCENT); - mLayoutParams.setTitle(TAG); - mLayoutParams.windowAnimations = 0; - LinearLayout layout = new LinearLayout(mContext); + mLayoutParams = createLayoutParams(context); + LinearLayout layout = new LinearLayout(context); layout.setLayoutParams(mLayoutParams); - mView = (UdfpsView) LayoutInflater.from(mContext).inflate(R.layout.udfps_view, layout, + mView = (UdfpsView) LayoutInflater.from(context).inflate(R.layout.udfps_view, layout, false); mView.setOnTouchListener(mOnTouchListener); - mHbmPath = mContext.getResources().getString(R.string.udfps_hbm_sysfs_path); - mHbmEnableCommand = mContext.getResources().getString(R.string.udfps_hbm_enable_command); - mHbmDisableCommand = mContext.getResources().getString(R.string.udfps_hbm_disable_command); + mHbmPath = context.getResources().getString(R.string.udfps_hbm_sysfs_path); + mHbmEnableCommand = context.getResources().getString(R.string.udfps_hbm_enable_command); + mHbmDisableCommand = context.getResources().getString(R.string.udfps_hbm_disable_command); + + // This range only consists of the minimum and maximum values, which only cover + // non-high-brightness mode. + float[] nitsRange = toFloatArray(context.getResources().obtainTypedArray( + com.android.internal.R.array.config_screenBrightnessNits)); + + // The last value of this range corresponds to the high-brightness mode. + float[] nitsAutoBrightnessValues = toFloatArray(context.getResources().obtainTypedArray( + com.android.internal.R.array.config_autoBrightnessDisplayValuesNits)); + + mHbmNits = nitsAutoBrightnessValues[nitsAutoBrightnessValues.length - 1]; + float[] hbmNitsRange = {nitsRange[0], mHbmNits}; + + // This range only consists of the minimum and maximum backlight values, which only apply + // in non-high-brightness mode. + float[] normalizedBacklightRange = normalizeBacklightRange( + context.getResources().getIntArray( + com.android.internal.R.array.config_screenBrightnessBacklight)); + + mBacklightToNitsSpline = Spline.createSpline(normalizedBacklightRange, nitsRange); + mNitsToHbmBacklightSpline = Spline.createSpline(hbmNitsRange, normalizedBacklightRange); + mDefaultBrightness = obtainDefaultBrightness(context); + + // TODO(b/160025856): move to the "dump" method. + Log.v(TAG, String.format("ctor | mNitsRange: [%f, %f]", nitsRange[0], nitsRange[1])); + Log.v(TAG, String.format("ctor | mHbmNitsRange: [%f, %f]", hbmNitsRange[0], + hbmNitsRange[1])); + Log.v(TAG, String.format("ctor | mNormalizedBacklightRange: [%f, %f]", + normalizedBacklightRange[0], normalizedBacklightRange[1])); mFingerprintManager.setUdfpsOverlayController(new UdfpsOverlayController()); mIsOverlayShowing = false; @@ -162,7 +191,34 @@ class UdfpsController { }); } + // Returns a value in the range of [0, 255]. + private int computeScrimOpacity() { + // Backlight setting can be NaN, -1.0f, and [0.0f, 1.0f]. + float backlightSetting = Settings.System.getFloatForUser(mContentResolver, + Settings.System.SCREEN_BRIGHTNESS_FLOAT, mDefaultBrightness, + UserHandle.USER_CURRENT); + + // Constrain the backlight setting to [0.0f, 1.0f]. + float backlightValue = MathUtils.constrain(backlightSetting, + PowerManager.BRIGHTNESS_MIN, + PowerManager.BRIGHTNESS_MAX); + + // Interpolate the backlight value to nits. + float nits = mBacklightToNitsSpline.interpolate(backlightValue); + + // Interpolate nits to a backlight value for a panel with enabled HBM. + float interpolatedHbmBacklightValue = mNitsToHbmBacklightSpline.interpolate(nits); + + float gammaCorrectedHbmBacklightValue = (float) Math.pow(interpolatedHbmBacklightValue, + 1.0f / DISPLAY_GAMMA); + float scrimOpacity = PowerManager.BRIGHTNESS_MAX - gammaCorrectedHbmBacklightValue; + + // Interpolate the opacity value from [0.0f, 1.0f] to [0, 255]. + return BrightnessSynchronizer.brightnessFloatToInt(scrimOpacity); + } + private void onFingerDown(int x, int y, float minor, float major) { + mView.setScrimAlpha(computeScrimOpacity()); try { FileWriter fw = new FileWriter(mHbmPath); fw.write(mHbmEnableCommand); @@ -185,4 +241,54 @@ class UdfpsController { Log.e(TAG, "onFingerUp | failed to disable HBM: " + e.getMessage()); } } + + private static WindowManager.LayoutParams createLayoutParams(Context context) { + Point displaySize = new Point(); + context.getDisplay().getRealSize(displaySize); + // TODO(b/160025856): move to the "dump" method. + Log.v(TAG, "createLayoutParams | display size: " + displaySize.x + "x" + + displaySize.y); + WindowManager.LayoutParams lp = new WindowManager.LayoutParams( + displaySize.x, + displaySize.y, + // TODO(b/152419866): Use the UDFPS window type when it becomes available. + WindowManager.LayoutParams.TYPE_BOOT_PROGRESS, + WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN + | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, + PixelFormat.TRANSLUCENT); + lp.setTitle(TAG); + lp.windowAnimations = 0; + return lp; + } + + private static float obtainDefaultBrightness(Context context) { + PowerManager powerManager = context.getSystemService(PowerManager.class); + if (powerManager == null) { + Log.e(TAG, "PowerManager is unavailable. Can't obtain default brightness."); + return 0f; + } + return MathUtils.constrain(powerManager.getBrightnessConstraint( + PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_DEFAULT), PowerManager.BRIGHTNESS_MIN, + PowerManager.BRIGHTNESS_MAX); + } + + private static float[] toFloatArray(TypedArray array) { + final int n = array.length(); + float[] vals = new float[n]; + for (int i = 0; i < n; i++) { + vals[i] = array.getFloat(i, PowerManager.BRIGHTNESS_OFF_FLOAT); + } + array.recycle(); + return vals; + } + + private static float[] normalizeBacklightRange(int[] backlight) { + final int n = backlight.length; + float[] normalizedBacklight = new float[n]; + for (int i = 0; i < n; i++) { + normalizedBacklight[i] = BrightnessSynchronizer.brightnessIntToFloat(backlight[i]); + } + return normalizedBacklight; + } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java index 8190550a74fc..d4e86d5dd234 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java @@ -79,7 +79,7 @@ public class UdfpsView extends View { mScrimRect = new Rect(); mScrimPaint = new Paint(0 /* flags */); - mScrimPaint.setARGB(110 /* a */, 0 /* r */, 0 /* g */, 0 /* b */); + mScrimPaint.setColor(Color.BLACK); mSensorRect = new RectF(); mSensorPaint = new Paint(0 /* flags */); @@ -136,6 +136,10 @@ public class UdfpsView extends View { && y < (mSensorY + mSensorRadius * mSensorTouchAreaCoefficient); } + void setScrimAlpha(int alpha) { + mScrimPaint.setAlpha(alpha); + } + boolean isFingerDown() { return mIsFingerDown; } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java index c5639ea6fcde..9c5f9fe8bcc0 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java @@ -139,7 +139,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi @IntDef({DISMISS_USER_GESTURE, DISMISS_AGED, DISMISS_TASK_FINISHED, DISMISS_BLOCKED, DISMISS_NOTIF_CANCEL, DISMISS_ACCESSIBILITY_ACTION, DISMISS_NO_LONGER_BUBBLE, DISMISS_USER_CHANGED, DISMISS_GROUP_CANCELLED, DISMISS_INVALID_INTENT, - DISMISS_OVERFLOW_MAX_REACHED, DISMISS_SHORTCUT_REMOVED, DISMISS_PACKAGE_REMOVED}) + DISMISS_OVERFLOW_MAX_REACHED, DISMISS_SHORTCUT_REMOVED, DISMISS_PACKAGE_REMOVED, + DISMISS_NO_BUBBLE_UP}) @Target({FIELD, LOCAL_VARIABLE, PARAMETER}) @interface DismissReason {} @@ -156,6 +157,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi static final int DISMISS_OVERFLOW_MAX_REACHED = 11; static final int DISMISS_SHORTCUT_REMOVED = 12; static final int DISMISS_PACKAGE_REMOVED = 13; + static final int DISMISS_NO_BUBBLE_UP = 14; private final Context mContext; private final NotificationEntryManager mNotificationEntryManager; @@ -1262,8 +1264,18 @@ public class BubbleController implements ConfigurationController.ConfigurationLi rankingMap.getRanking(key, mTmpRanking); boolean isActiveBubble = mBubbleData.hasAnyBubbleWithKey(key); if (isActiveBubble && !mTmpRanking.canBubble()) { - mBubbleData.dismissBubbleWithKey(entry.getKey(), - BubbleController.DISMISS_BLOCKED); + // If this entry is no longer allowed to bubble, dismiss with the BLOCKED reason. + // This means that the app or channel's ability to bubble has been revoked. + mBubbleData.dismissBubbleWithKey( + key, BubbleController.DISMISS_BLOCKED); + } else if (isActiveBubble + && !mNotificationInterruptStateProvider.shouldBubbleUp(entry)) { + // If this entry is allowed to bubble, but cannot currently bubble up, dismiss it. + // This happens when DND is enabled and configured to hide bubbles. Dismissing with + // the reason DISMISS_NO_BUBBLE_UP will retain the underlying notification, so that + // the bubble will be re-created if shouldBubbleUp returns true. + mBubbleData.dismissBubbleWithKey( + key, BubbleController.DISMISS_NO_BUBBLE_UP); } else if (entry != null && mTmpRanking.isBubble() && !isActiveBubble) { entry.setFlagBubble(true); onEntryUpdated(entry); @@ -1340,8 +1352,10 @@ public class BubbleController implements ConfigurationController.ConfigurationLi mStackView.removeBubble(bubble); } - // If the bubble is removed for user switching, leave the notification in place. - if (reason == DISMISS_USER_CHANGED) { + // Leave the notification in place if we're dismissing due to user switching, or + // because DND is suppressing the bubble. In both of those cases, we need to be able + // to restore the bubble from the notification later. + if (reason == DISMISS_USER_CHANGED || reason == DISMISS_NO_BUBBLE_UP) { continue; } if (reason == DISMISS_NOTIF_CANCEL) { diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java index 3d31070905d0..21bcfcd9fdaf 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java @@ -31,6 +31,7 @@ import android.view.Choreographer; import android.view.IWindowManager; import android.view.LayoutInflater; import android.view.WindowManager; +import android.view.accessibility.AccessibilityManager; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEventLogger; @@ -40,6 +41,8 @@ import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.Prefs; import com.android.systemui.accessibility.ModeSwitchesController; +import com.android.systemui.accessibility.SystemActions; +import com.android.systemui.assist.AssistManager; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger; import com.android.systemui.dagger.qualifiers.Background; @@ -47,25 +50,38 @@ import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.doze.AlwaysOnDisplayPolicy; import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.KeyguardViewMediator; +import com.android.systemui.model.SysUiState; +import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.plugins.PluginInitializerImpl; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.recents.OverviewProxyService; +import com.android.systemui.recents.Recents; import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.shared.plugins.PluginManagerImpl; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.DevicePolicyManagerWrapper; +import com.android.systemui.stackdivider.Divider; import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.NavigationBarController; +import com.android.systemui.navigationbar.NavigationBarController; +import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.phone.AutoHideController; import com.android.systemui.statusbar.phone.ConfigurationControllerImpl; +import com.android.systemui.statusbar.phone.ShadeController; +import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DataSaverController; +import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.util.leak.LeakDetector; +import java.util.Optional; import java.util.concurrent.Executor; import javax.inject.Named; import javax.inject.Singleton; +import dagger.Lazy; import dagger.Module; import dagger.Provides; @@ -159,8 +175,49 @@ public class DependencyProvider { @Singleton @Provides public NavigationBarController provideNavigationBarController(Context context, - @Main Handler mainHandler, CommandQueue commandQueue) { - return new NavigationBarController(context, mainHandler, commandQueue); + WindowManager windowManager, + Lazy<AssistManager> assistManagerLazy, + AccessibilityManager accessibilityManager, + AccessibilityManagerWrapper accessibilityManagerWrapper, + DeviceProvisionedController deviceProvisionedController, + MetricsLogger metricsLogger, + OverviewProxyService overviewProxyService, + NavigationModeController navigationModeController, + StatusBarStateController statusBarStateController, + SysUiState sysUiFlagsContainer, + BroadcastDispatcher broadcastDispatcher, + CommandQueue commandQueue, + Divider divider, + Optional<Recents> recentsOptional, + Lazy<StatusBar> statusBarLazy, + ShadeController shadeController, + NotificationRemoteInputManager notificationRemoteInputManager, + SystemActions systemActions, + @Main Handler mainHandler, + UiEventLogger uiEventLogger, + ConfigurationController configurationController) { + return new NavigationBarController(context, + windowManager, + assistManagerLazy, + accessibilityManager, + accessibilityManagerWrapper, + deviceProvisionedController, + metricsLogger, + overviewProxyService, + navigationModeController, + statusBarStateController, + sysUiFlagsContainer, + broadcastDispatcher, + commandQueue, + divider, + recentsOptional, + statusBarLazy, + shadeController, + notificationRemoteInputManager, + systemActions, + mainHandler, + uiEventLogger, + configurationController); } @Singleton @@ -230,6 +287,12 @@ public class DependencyProvider { } /** */ + @Provides + public SystemActions providesSystemActions(Context context) { + return new SystemActions(context); + } + + /** */ @Singleton @Provides public Choreographer providesChoreographer() { diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java index 9fdbb6daca51..9c55095e85e5 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java @@ -16,9 +16,6 @@ package com.android.systemui.dagger; -import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME; - -import android.content.ContentProvider; import android.content.Context; import com.android.systemui.BootCompleteCacheImpl; @@ -26,14 +23,12 @@ import com.android.systemui.Dependency; import com.android.systemui.InitController; import com.android.systemui.SystemUIAppComponentFactory; import com.android.systemui.dump.DumpManager; -import com.android.systemui.fragments.FragmentService; import com.android.systemui.keyguard.KeyguardSliceProvider; import com.android.systemui.onehanded.dagger.OneHandedModule; import com.android.systemui.pip.phone.dagger.PipModule; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.util.InjectionInflationController; -import javax.inject.Named; import javax.inject.Singleton; import dagger.BindsInstance; @@ -42,6 +37,7 @@ import dagger.Component; /** * Root component for Dagger injection. */ +// TODO(b/162923491): Move most of these modules to SysUIComponent. @Singleton @Component(modules = { DefaultComponentBinder.class, @@ -52,21 +48,32 @@ import dagger.Component; SystemServicesModule.class, SystemUIBinder.class, SystemUIModule.class, - SystemUIDefaultModule.class}) -public interface SystemUIRootComponent { + SystemUIDefaultModule.class, + WMModule.class}) +public interface GlobalRootComponent { /** - * Builder for a SystemUIRootComponent. + * Builder for a GlobalRootComponent. */ @Component.Builder interface Builder { @BindsInstance Builder context(Context context); - SystemUIRootComponent build(); + GlobalRootComponent build(); } /** + * Builder for a WMComponent. + */ + WMComponent.Builder getWMComponentBuilder(); + + /** + * Builder for a SysuiComponent. + */ + SysUIComponent.Builder getSysUIComponent(); + + /** * Provides a BootCompleteCache. */ @Singleton @@ -95,28 +102,15 @@ public interface SystemUIRootComponent { DumpManager createDumpManager(); /** - * FragmentCreator generates all Fragments that need injection. - */ - @Singleton - FragmentService.FragmentCreator createFragmentCreator(); - - - /** * Creates a InitController. */ @Singleton InitController getInitController(); /** - * ViewCreator generates all Views that need injection. - */ - InjectionInflationController.ViewCreator createViewCreator(); - - /** - * Whether notification long press is allowed. + * ViewInstanceCreator generates all Views that need injection. */ - @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) - boolean allowNotificationLongPressName(); + InjectionInflationController.ViewInstanceCreator.Factory createViewInstanceCreatorFactory(); /** * Member injection into the supplied argument. @@ -126,10 +120,5 @@ public interface SystemUIRootComponent { /** * Member injection into the supplied argument. */ - void inject(ContentProvider contentProvider); - - /** - * Member injection into the supplied argument. - */ void inject(KeyguardSliceProvider keyguardSliceProvider); } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java new file mode 100644 index 000000000000..9b527bfeda27 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2019 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.dagger; + +import dagger.Subcomponent; + +/** + * Dagger Subcomponent for Core SysUI. + */ +@SysUISingleton +@Subcomponent(modules = {}) +public interface SysUIComponent { + + /** + * Builder for a SysUIComponent. + */ + @Subcomponent.Builder + interface Builder { + SysUIComponent build(); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUISingleton.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUISingleton.java new file mode 100644 index 000000000000..a4b33427cbda --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUISingleton.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2020 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.dagger; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; + +import javax.inject.Scope; + +/** + * Scope annotation for singleton items within the SysUIComponent. + */ +@Documented +@Retention(RUNTIME) +@Scope +public @interface SysUISingleton { +} diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java index 803e56db8ff3..56219c3356fc 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java @@ -29,6 +29,7 @@ import com.android.keyguard.KeyguardViewController; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.demomode.DemoModeController; import com.android.systemui.dock.DockManager; import com.android.systemui.dock.DockManagerImpl; import com.android.systemui.doze.DozeHost; @@ -72,7 +73,14 @@ import dagger.Provides; * A dagger module for injecting default implementations of components of System UI that may be * overridden by the System UI implementation. */ -@Module(includes = {DividerModule.class, QSModule.class, WindowManagerShellModule.class}) +@Module(includes = { + DividerModule.class, + QSModule.class, + WindowManagerShellModule.class + }, + subcomponents = { + SysUIComponent.class + }) public abstract class SystemUIDefaultModule { @Singleton @@ -92,12 +100,22 @@ public abstract class SystemUIDefaultModule { @Provides @Singleton - static BatteryController provideBatteryController(Context context, - EnhancedEstimates enhancedEstimates, PowerManager powerManager, - BroadcastDispatcher broadcastDispatcher, @Main Handler mainHandler, + static BatteryController provideBatteryController( + Context context, + EnhancedEstimates enhancedEstimates, + PowerManager powerManager, + BroadcastDispatcher broadcastDispatcher, + DemoModeController demoModeController, + @Main Handler mainHandler, @Background Handler bgHandler) { - BatteryController bC = new BatteryControllerImpl(context, enhancedEstimates, powerManager, - broadcastDispatcher, mainHandler, bgHandler); + BatteryController bC = new BatteryControllerImpl( + context, + enhancedEstimates, + powerManager, + broadcastDispatcher, + demoModeController, + mainHandler, + bgHandler); bC.init(); return bC; } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index f774358b69fb..a46e182327f8 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -24,8 +24,10 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.BootCompleteCache; import com.android.systemui.BootCompleteCacheImpl; import com.android.systemui.assist.AssistModule; +import com.android.systemui.demomode.dagger.DemoModeModule; import com.android.systemui.doze.dagger.DozeComponent; import com.android.systemui.dump.DumpManager; +import com.android.systemui.fragments.FragmentService; import com.android.systemui.log.dagger.LogModule; import com.android.systemui.model.SysUiState; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -64,6 +66,7 @@ import dagger.Provides; @Module(includes = { AssistModule.class, ConcurrencyModule.class, + DemoModeModule.class, LogModule.class, PeopleHubModule.class, SensorModule.class, @@ -74,7 +77,8 @@ import dagger.Provides; NotificationRowComponent.class, DozeComponent.class, ExpandableNotificationRowComponent.class, - NotificationShelfComponent.class}) + NotificationShelfComponent.class, + FragmentService.FragmentCreator.class}) public abstract class SystemUIModule { @Binds diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java new file mode 100644 index 000000000000..929b61a3421c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2019 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.dagger; + +import dagger.Subcomponent; + +/** + * Dagger Subcomponent for WindowManager. + */ +@WMSingleton +@Subcomponent(modules = {}) +public interface WMComponent { + + /** + * Builder for a WMComponent. + */ + @Subcomponent.Builder + interface Builder { + WMComponent build(); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMModule.java b/packages/SystemUI/src/com/android/systemui/dagger/WMModule.java new file mode 100644 index 000000000000..2894780e04b8 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/dagger/WMModule.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2020 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.dagger; + +import dagger.Module; + +/** + * Dagger module for including the WMComponent. + */ +@Module(subcomponents = {WMComponent.class}) +public abstract class WMModule { +} diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMSingleton.java b/packages/SystemUI/src/com/android/systemui/dagger/WMSingleton.java new file mode 100644 index 000000000000..7292b9e459e0 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/dagger/WMSingleton.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2020 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.dagger; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; + +import javax.inject.Scope; + +/** + * Scope annotation for singleton items within the WMComponent. + */ +@Documented +@Retention(RUNTIME) +@Scope +public @interface WMSingleton { +} diff --git a/packages/SystemUI/src/com/android/systemui/demomode/DemoMode.java b/packages/SystemUI/src/com/android/systemui/demomode/DemoMode.java new file mode 100644 index 000000000000..672ade2655a3 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/demomode/DemoMode.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2020 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.demomode; + +import com.google.android.collect.Lists; + +import java.util.ArrayList; +import java.util.List; + +/** + * Interface defining what it means to implement DemoMode. A DemoMode implementation should + * register with DemoModeController, providing a list of commands for wish to listen. + * + * If you only need to listen to commands, but *do not* care about demo mode state changes, you + * can implement DemoModeCommandReceiver instead + */ +public interface DemoMode extends DemoModeCommandReceiver { + + List<String> NO_COMMANDS = new ArrayList<>(); + + /** Provide a set of commands to listen to, only acceptable values are the COMMAND_* keys */ + default List<String> demoCommands() { + return NO_COMMANDS; + } + + String ACTION_DEMO = "com.android.systemui.demo"; + + String EXTRA_COMMAND = "command"; + + /** Enter and exit are non-register-able; override started/finished to observe these states */ + String COMMAND_ENTER = "enter"; + String COMMAND_EXIT = "exit"; + + /** Observable commands to register a listener for */ + String COMMAND_CLOCK = "clock"; + String COMMAND_BATTERY = "battery"; + String COMMAND_NETWORK = "network"; + String COMMAND_BARS = "bars"; + String COMMAND_STATUS = "status"; + String COMMAND_NOTIFICATIONS = "notifications"; + String COMMAND_VOLUME = "volume"; + String COMMAND_OPERATOR = "operator"; + + /** New keys need to be added here */ + List<String> COMMANDS = Lists.newArrayList( + COMMAND_BARS, + COMMAND_BATTERY, + COMMAND_CLOCK, + COMMAND_NETWORK, + COMMAND_NOTIFICATIONS, + COMMAND_OPERATOR, + COMMAND_STATUS, + COMMAND_VOLUME + ); +} + diff --git a/packages/SystemUI/src/com/android/systemui/demomode/DemoModeAvailabilityTracker.kt b/packages/SystemUI/src/com/android/systemui/demomode/DemoModeAvailabilityTracker.kt new file mode 100644 index 000000000000..16f415070b45 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/demomode/DemoModeAvailabilityTracker.kt @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2020 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.demomode + +import android.content.Context +import android.database.ContentObserver +import android.os.Handler +import android.os.Looper +import android.provider.Settings + +/** + * Class to track the availability of [DemoMode]. Use this class to track the availability and + * on/off state for DemoMode + * + * This class works by wrapping a content observer for the relevant keys related to DemoMode + * availability and current on/off state, and triggering callbacks. + */ +abstract class DemoModeAvailabilityTracker(val context: Context) { + var isInDemoMode = false + var isDemoModeAvailable = false + + init { + isInDemoMode = checkIsDemoModeOn() + isDemoModeAvailable = checkIsDemoModeAllowed() + } + + fun startTracking() { + val resolver = context.contentResolver + resolver.registerContentObserver( + Settings.Global.getUriFor(DEMO_MODE_ALLOWED), false, allowedObserver) + resolver.registerContentObserver( + Settings.Global.getUriFor(DEMO_MODE_ON), false, onObserver) + } + + fun stopTracking() { + val resolver = context.contentResolver + resolver.unregisterContentObserver(allowedObserver) + resolver.unregisterContentObserver(onObserver) + } + + abstract fun onDemoModeAvailabilityChanged() + abstract fun onDemoModeStarted() + abstract fun onDemoModeFinished() + + private fun checkIsDemoModeAllowed(): Boolean { + return Settings.Global + .getInt(context.contentResolver, DEMO_MODE_ALLOWED, 0) != 0 + } + + private fun checkIsDemoModeOn(): Boolean { + return Settings.Global.getInt(context.contentResolver, DEMO_MODE_ON, 0) != 0 + } + + private val allowedObserver = object : ContentObserver(Handler(Looper.getMainLooper())) { + override fun onChange(selfChange: Boolean) { + val allowed = checkIsDemoModeAllowed() + if (DEBUG) { + android.util.Log.d(TAG, "onChange: DEMO_MODE_ALLOWED changed: $allowed") + } + + if (isDemoModeAvailable == allowed) { + return + } + + isDemoModeAvailable = allowed + onDemoModeAvailabilityChanged() + } + } + + private val onObserver = object : ContentObserver(Handler(Looper.getMainLooper())) { + override fun onChange(selfChange: Boolean) { + val on = checkIsDemoModeOn() + + if (DEBUG) { + android.util.Log.d(TAG, "onChange: DEMO_MODE_ON changed: $on") + } + + if (isInDemoMode == on) { + return + } + + isInDemoMode = on + if (on) { + onDemoModeStarted() + } else { + onDemoModeFinished() + } + } + } +} + +private const val TAG = "DemoModeAvailabilityTracker" +private const val DEMO_MODE_ALLOWED = "sysui_demo_allowed" +private const val DEMO_MODE_ON = "sysui_tuner_demo_on" +private const val DEBUG = false diff --git a/packages/SystemUI/src/com/android/systemui/demomode/DemoModeCommandReceiver.java b/packages/SystemUI/src/com/android/systemui/demomode/DemoModeCommandReceiver.java new file mode 100644 index 000000000000..609536a4b8e8 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/demomode/DemoModeCommandReceiver.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2020 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.demomode; + +import android.os.Bundle; + +/** Defines the basic DemoMode command interface */ +public interface DemoModeCommandReceiver { + /** Override point to observe demo mode commands */ + void dispatchDemoCommand(String command, Bundle args); + + /** + * Demo mode starts due to receiving [COMMAND_ENTER] or receiving any other demo mode command + * while [DEMO_MODE_ALLOWED] is true but demo mode is off + */ + default void onDemoModeStarted() {} + + /** Demo mode exited */ + default void onDemoModeFinished() {} + +} diff --git a/packages/SystemUI/src/com/android/systemui/demomode/DemoModeController.kt b/packages/SystemUI/src/com/android/systemui/demomode/DemoModeController.kt new file mode 100644 index 000000000000..c76f55631ac9 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/demomode/DemoModeController.kt @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2020 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.demomode + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.os.Bundle +import android.os.UserHandle +import android.util.Log +import com.android.systemui.Dumpable +import com.android.systemui.demomode.DemoMode.ACTION_DEMO +import com.android.systemui.dump.DumpManager +import com.android.systemui.statusbar.policy.CallbackController +import com.android.systemui.util.Assert +import com.android.systemui.util.settings.GlobalSettings +import java.io.FileDescriptor +import java.io.PrintWriter + +/** + * Handles system broadcasts for [DemoMode] + * + * Injected via [DemoModeModule] + */ +class DemoModeController constructor( + private val context: Context, + private val dumpManager: DumpManager, + private val globalSettings: GlobalSettings +) : CallbackController<DemoMode>, Dumpable { + + // Var updated when the availability tracker changes, or when we enter/exit demo mode in-process + var isInDemoMode = false + + var isAvailable = false + get() = tracker.isDemoModeAvailable + + private var initialized = false + + private val receivers = mutableListOf<DemoMode>() + private val receiverMap: Map<String, MutableList<DemoMode>> + + init { + val m = mutableMapOf<String, MutableList<DemoMode>>() + DemoMode.COMMANDS.map { command -> + m.put(command, mutableListOf()) + } + receiverMap = m + } + + fun initialize() { + if (initialized) { + throw IllegalStateException("Already initialized") + } + + initialized = true + + dumpManager.registerDumpable(TAG, this) + + // Due to DemoModeFragment running in systemui:tuner process, we have to observe for + // content changes to know if the setting turned on or off + tracker.startTracking() + + // TODO: We should probably exit demo mode if we booted up with it on + isInDemoMode = tracker.isInDemoMode + + val demoFilter = IntentFilter() + demoFilter.addAction(ACTION_DEMO) + context.registerReceiverAsUser(broadcastReceiver, UserHandle.ALL, demoFilter, + android.Manifest.permission.DUMP, null) + } + + override fun addCallback(listener: DemoMode) { + Assert.isMainThread() + + // Register this listener for its commands + val commands = listener.demoCommands() + + commands.forEach { command -> + if (!receiverMap.containsKey(command)) { + throw IllegalStateException("Command ($command) not recognized. " + + "See DemoMode.java for valid commands") + } + + receiverMap[command]!!.add(listener) + } + + receivers.add(listener) + if (isInDemoMode) { + listener.onDemoModeStarted() + } + } + + override fun removeCallback(listener: DemoMode) { + Assert.isMainThread() + + listener.demoCommands().forEach { command -> + receiverMap[command]!!.remove(listener) + } + + receivers.remove(listener) + } + + private fun setIsDemoModeAllowed(enabled: Boolean) { + // Turn off demo mode if it was on + if (isInDemoMode && !enabled) { + requestFinishDemoMode() + } + } + + private fun enterDemoMode() { + isInDemoMode = true + Assert.isMainThread() + receivers.forEach { r -> + r.onDemoModeStarted() + } + } + + private fun exitDemoMode() { + isInDemoMode = false + Assert.isMainThread() + receivers.forEach { r -> + r.onDemoModeFinished() + } + } + + fun dispatchDemoCommand(command: String, args: Bundle) { + Assert.isMainThread() + + if (DEBUG) { + Log.d(TAG, "dispatchDemoCommand: $command, args=$args") + } + + if (!isAvailable) { + return + } + + if (command == DemoMode.COMMAND_ENTER) { + enterDemoMode() + } else if (command == DemoMode.COMMAND_EXIT) { + exitDemoMode() + } else if (!isInDemoMode) { + enterDemoMode() + } + + // See? demo mode is easy now, you just notify the listeners when their command is called + receiverMap[command]!!.forEach { receiver -> + receiver.dispatchDemoCommand(command, args) + } + } + + override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) { + pw.println("DemoModeController state -") + pw.println(" isInDemoMode=$isInDemoMode") + pw.println(" isDemoModeAllowed=$isAvailable") + pw.print(" receivers=[") + receivers.forEach { recv -> + pw.print(" ${recv.javaClass.simpleName}") + } + pw.println(" ]") + pw.println(" receiverMap= [") + receiverMap.keys.forEach { command -> + pw.print(" $command : [") + val recvs = receiverMap[command]!!.map { receiver -> + receiver.javaClass.simpleName + }.joinToString(",") + pw.println("$recvs ]") + } + } + + private val tracker = object : DemoModeAvailabilityTracker(context) { + override fun onDemoModeAvailabilityChanged() { + setIsDemoModeAllowed(isDemoModeAvailable) + } + + override fun onDemoModeStarted() { + if (this@DemoModeController.isInDemoMode != isInDemoMode) { + enterDemoMode() + } + } + + override fun onDemoModeFinished() { + if (this@DemoModeController.isInDemoMode != isInDemoMode) { + exitDemoMode() + } + } + } + + private val broadcastReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + if (DEBUG) { + Log.v(TAG, "onReceive: $intent") + } + + val action = intent.action + if (!ACTION_DEMO.equals(action)) { + return + } + + val bundle = intent.extras ?: return + val command = bundle.getString("command", "").trim().toLowerCase() + if (command.length == 0) { + return + } + + try { + dispatchDemoCommand(command, bundle) + } catch (t: Throwable) { + Log.w(TAG, "Error running demo command, intent=$intent $t") + } + } + } + + fun requestSetDemoModeAllowed(allowed: Boolean) { + setGlobal(DEMO_MODE_ALLOWED, if (allowed) 1 else 0) + } + + fun requestStartDemoMode() { + setGlobal(DEMO_MODE_ON, 1) + } + + fun requestFinishDemoMode() { + setGlobal(DEMO_MODE_ON, 0) + } + + private fun setGlobal(key: String, value: Int) { + globalSettings.putInt(key, value) + } +} + +private const val TAG = "DemoModeController" +private const val DEMO_MODE_ALLOWED = "sysui_demo_allowed" +private const val DEMO_MODE_ON = "sysui_tuner_demo_on" + +private const val DEBUG = false diff --git a/packages/SystemUI/src/com/android/systemui/demomode/dagger/DemoModeModule.java b/packages/SystemUI/src/com/android/systemui/demomode/dagger/DemoModeModule.java new file mode 100644 index 000000000000..9270b8843c80 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/demomode/dagger/DemoModeModule.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2020 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.demomode.dagger; + +import android.content.Context; + +import com.android.systemui.demomode.DemoModeController; +import com.android.systemui.dump.DumpManager; +import com.android.systemui.util.settings.GlobalSettings; + +import javax.inject.Singleton; + +import dagger.Module; +import dagger.Provides; + +/** + * Dagger module providing {@link DemoModeController} + */ +@Module +public abstract class DemoModeModule { + /** Provides DemoModeController */ + @Provides + @Singleton + static DemoModeController provideDemoModeController( + Context context, + DumpManager dumpManager, + GlobalSettings globalSettings) { + DemoModeController dmc = new DemoModeController(context, dumpManager, globalSettings); + dmc.initialize(); + return /*run*/dmc; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java index ae200763b3b0..e88886933d5f 100644 --- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java +++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java @@ -21,9 +21,7 @@ import android.util.ArrayMap; import android.view.View; import com.android.systemui.Dumpable; -import com.android.systemui.dagger.SystemUIRootComponent; import com.android.systemui.qs.QSFragment; -import com.android.systemui.statusbar.phone.NavigationBarFragment; import com.android.systemui.statusbar.policy.ConfigurationController; import java.io.FileDescriptor; @@ -61,9 +59,9 @@ public class FragmentService implements Dumpable { }; @Inject - public FragmentService(SystemUIRootComponent rootComponent, + public FragmentService(FragmentCreator.Factory fragmentCreatorFactory, ConfigurationController configurationController) { - mFragmentCreator = rootComponent.createFragmentCreator(); + mFragmentCreator = fragmentCreatorFactory.build(); initInjectionMap(); configurationController.addCallback(mConfigurationListener); } @@ -121,10 +119,11 @@ public class FragmentService implements Dumpable { */ @Subcomponent public interface FragmentCreator { - /** - * Inject a NavigationBarFragment. - */ - NavigationBarFragment createNavigationBarFragment(); + /** Factory for creating a FragmentCreator. */ + @Subcomponent.Factory + interface Factory { + FragmentCreator build(); + } /** * Inject a QSFragment. */ diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java index 3a37c0fd4634..daef2c506ad3 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java @@ -52,7 +52,6 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.SystemUIAppComponentFactory; -import com.android.systemui.SystemUIFactory; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.StatusBarState; @@ -72,6 +71,9 @@ import javax.inject.Inject; /** * Simple Slice provider that shows the current date. + * + * Injection is handled by {@link SystemUIAppComponentFactory} + + * {@link com.android.systemui.dagger.GlobalRootComponent#inject(KeyguardSliceProvider)}. */ public class KeyguardSliceProvider extends SliceProvider implements NextAlarmController.NextAlarmChangeCallback, ZenModeController.Callback, @@ -298,7 +300,8 @@ public class KeyguardSliceProvider extends SliceProvider implements @Override public boolean onCreateSliceProvider() { mContextAvailableCallback.onContextAvailable(getContext()); - inject(); + mMediaWakeLock = new SettableWakeLock(WakeLock.createPartial(getContext(), "media"), + "media"); synchronized (KeyguardSliceProvider.sInstanceLock) { KeyguardSliceProvider oldInstance = KeyguardSliceProvider.sInstance; if (oldInstance != null) { @@ -319,13 +322,6 @@ public class KeyguardSliceProvider extends SliceProvider implements } @VisibleForTesting - protected void inject() { - SystemUIFactory.getInstance().getRootComponent().inject(this); - mMediaWakeLock = new SettableWakeLock(WakeLock.createPartial(getContext(), "media"), - "media"); - } - - @VisibleForTesting protected void onDestroy() { synchronized (KeyguardSliceProvider.sInstanceLock) { mNextAlarmController.removeCallback(this); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 75f4809d752f..6214a6448287 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -85,7 +85,6 @@ import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.SystemUI; -import com.android.systemui.SystemUIFactory; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.dump.DumpManager; @@ -94,7 +93,7 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.statusbar.phone.BiometricUnlockController; import com.android.systemui.statusbar.phone.KeyguardBypassController; -import com.android.systemui.statusbar.phone.NavigationModeController; +import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.statusbar.phone.NotificationPanelViewController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.util.DeviceConfigProxy; @@ -229,6 +228,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { /** TrustManager for letting it know when we change visibility */ private final TrustManager mTrustManager; + private final InjectionInflationController mInjectionInflationController; /** * Used to keep the device awake while to ensure the keyguard finishes opening before @@ -723,7 +723,8 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { @UiBackground Executor uiBgExecutor, PowerManager powerManager, TrustManager trustManager, DeviceConfigProxy deviceConfig, - NavigationModeController navigationModeController) { + NavigationModeController navigationModeController, + InjectionInflationController injectionInflationController) { super(context); mFalsingManager = falsingManager; mLockPatternUtils = lockPatternUtils; @@ -734,6 +735,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { mUpdateMonitor = keyguardUpdateMonitor; mPM = powerManager; mTrustManager = trustManager; + mInjectionInflationController = injectionInflationController; dumpManager.registerDumpable(getClass().getName(), this); mDeviceConfig = deviceConfig; mShowHomeOverLockscreen = mDeviceConfig.getBoolean( @@ -773,10 +775,8 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable { mContext.registerReceiver(mDelayedLockBroadcastReceiver, delayedActionFilter, SYSTEMUI_PERMISSION, null /* scheduler */); - InjectionInflationController injectionInflationController = - new InjectionInflationController(SystemUIFactory.getInstance().getRootComponent()); mKeyguardDisplayManager = new KeyguardDisplayManager(mContext, - injectionInflationController); + mInjectionInflationController); mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java index 83c95b77b716..fc789a6fa4bc 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -29,9 +29,10 @@ import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.plugins.FalsingManager; -import com.android.systemui.statusbar.phone.NavigationModeController; +import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.util.DeviceConfigProxy; +import com.android.systemui.util.InjectionInflationController; import java.util.concurrent.Executor; @@ -64,7 +65,8 @@ public class KeyguardModule { TrustManager trustManager, @UiBackground Executor uiBgExecutor, DeviceConfigProxy deviceConfig, - NavigationModeController navigationModeController) { + NavigationModeController navigationModeController, + InjectionInflationController injectionInflationController) { return new KeyguardViewMediator( context, falsingManager, @@ -78,6 +80,7 @@ public class KeyguardModule { powerManager, trustManager, deviceConfig, - navigationModeController); + navigationModeController, + injectionInflationController); } } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt index 7f610d1a8467..b993faabe9b1 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt @@ -10,6 +10,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.LinearLayout +import androidx.annotation.VisibleForTesting import com.android.systemui.R import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.plugins.ActivityStarter @@ -21,6 +22,7 @@ import com.android.systemui.util.Utils import com.android.systemui.util.animation.UniqueObjectHostView import com.android.systemui.util.animation.requiresRemeasuring import com.android.systemui.util.concurrency.DelayableExecutor +import java.util.TreeMap import javax.inject.Inject import javax.inject.Provider import javax.inject.Singleton @@ -102,9 +104,7 @@ class MediaCarouselController @Inject constructor( private val mediaCarousel: MediaScrollView private val mediaCarouselScrollHandler: MediaCarouselScrollHandler val mediaFrame: ViewGroup - val mediaPlayers: MutableMap<String, MediaControlPanel> = mutableMapOf() private lateinit var settingsButton: View - private val mediaData: MutableMap<String, MediaData> = mutableMapOf() private val mediaContent: ViewGroup private val pageIndicator: PageIndicator private val visualStabilityCallback: VisualStabilityManager.Callback @@ -122,7 +122,7 @@ class MediaCarouselController @Inject constructor( set(value) { if (field != value) { field = value - for (player in mediaPlayers.values) { + for (player in MediaPlayerData.players()) { player.setListening(field) } } @@ -167,20 +167,18 @@ class MediaCarouselController @Inject constructor( true /* persistent */) mediaManager.addListener(object : MediaDataManager.Listener { override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) { - oldKey?.let { mediaData.remove(it) } if (!data.active && !Utils.useMediaResumption(context)) { // This view is inactive, let's remove this! This happens e.g when dismissing / // timing out a view. We still have the data around because resumption could // be on, but we should save the resources and release this. + oldKey?.let { MediaPlayerData.removeMediaPlayer(it) } onMediaDataRemoved(key) } else { - mediaData.put(key, data) addOrUpdatePlayer(key, oldKey, data) } } override fun onMediaDataRemoved(key: String) { - mediaData.remove(key) removePlayer(key) } }) @@ -223,53 +221,36 @@ class MediaCarouselController @Inject constructor( } private fun reorderAllPlayers() { - for (mediaPlayer in mediaPlayers.values) { - val view = mediaPlayer.view?.player - if (mediaPlayer.isPlaying && mediaContent.indexOfChild(view) != 0) { - mediaContent.removeView(view) - mediaContent.addView(view, 0) + mediaContent.removeAllViews() + for (mediaPlayer in MediaPlayerData.players()) { + mediaPlayer.view?.let { + mediaContent.addView(it.player) } } mediaCarouselScrollHandler.onPlayersChanged() } private fun addOrUpdatePlayer(key: String, oldKey: String?, data: MediaData) { - // If the key was changed, update entry - val oldData = mediaPlayers[oldKey] - if (oldData != null) { - val oldData = mediaPlayers.remove(oldKey) - mediaPlayers.put(key, oldData!!)?.let { - Log.wtf(TAG, "new key $key already exists when migrating from $oldKey") - } - } - var existingPlayer = mediaPlayers[key] + val existingPlayer = MediaPlayerData.getMediaPlayer(key, oldKey) if (existingPlayer == null) { - existingPlayer = mediaControlPanelFactory.get() - existingPlayer.attach(PlayerViewHolder.create(LayoutInflater.from(context), - mediaContent)) - existingPlayer.mediaViewController.sizeChangedListener = this::updateCarouselDimensions - mediaPlayers[key] = existingPlayer + var newPlayer = mediaControlPanelFactory.get() + newPlayer.attach(PlayerViewHolder.create(LayoutInflater.from(context), mediaContent)) + newPlayer.mediaViewController.sizeChangedListener = this::updateCarouselDimensions + MediaPlayerData.addMediaPlayer(key, data, newPlayer) val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) - existingPlayer.view?.player?.setLayoutParams(lp) - existingPlayer.bind(data) - existingPlayer.setListening(currentlyExpanded) - updatePlayerToState(existingPlayer, noAnimation = true) - if (existingPlayer.isPlaying) { - mediaContent.addView(existingPlayer.view?.player, 0) - } else { - mediaContent.addView(existingPlayer.view?.player) - } + newPlayer.view?.player?.setLayoutParams(lp) + newPlayer.bind(data) + newPlayer.setListening(currentlyExpanded) + updatePlayerToState(newPlayer, noAnimation = true) + reorderAllPlayers() } else { existingPlayer.bind(data) - if (existingPlayer.isPlaying && - mediaContent.indexOfChild(existingPlayer.view?.player) != 0) { - if (visualStabilityManager.isReorderingAllowed) { - mediaContent.removeView(existingPlayer.view?.player) - mediaContent.addView(existingPlayer.view?.player, 0) - } else { - needsReordering = true - } + MediaPlayerData.addMediaPlayer(key, data, existingPlayer) + if (visualStabilityManager.isReorderingAllowed) { + reorderAllPlayers() + } else { + needsReordering = true } } updatePageIndicator() @@ -277,13 +258,13 @@ class MediaCarouselController @Inject constructor( mediaCarousel.requiresRemeasuring = true // Check postcondition: mediaContent should have the same number of children as there are // elements in mediaPlayers. - if (mediaPlayers.size != mediaContent.childCount) { + if (MediaPlayerData.players().size != mediaContent.childCount) { Log.wtf(TAG, "Size of players list and number of views in carousel are out of sync") } } private fun removePlayer(key: String) { - val removed = mediaPlayers.remove(key) + val removed = MediaPlayerData.removeMediaPlayer(key) removed?.apply { mediaCarouselScrollHandler.onPrePlayerRemoved(removed) mediaContent.removeView(removed.view?.player) @@ -294,12 +275,7 @@ class MediaCarouselController @Inject constructor( } private fun recreatePlayers() { - // Note that this will scramble the order of players. Actively playing sessions will, at - // least, still be put in the front. If we want to maintain order, then more work is - // needed. - mediaData.forEach { - key, data -> - removePlayer(key) + MediaPlayerData.mediaData().forEach { (key, data) -> addOrUpdatePlayer(key = key, oldKey = null, data = data) } } @@ -337,7 +313,7 @@ class MediaCarouselController @Inject constructor( currentStartLocation = startLocation currentEndLocation = endLocation currentTransitionProgress = progress - for (mediaPlayer in mediaPlayers.values) { + for (mediaPlayer in MediaPlayerData.players()) { updatePlayerToState(mediaPlayer, immediately) } maybeResetSettingsCog() @@ -386,7 +362,7 @@ class MediaCarouselController @Inject constructor( private fun updateCarouselDimensions() { var width = 0 var height = 0 - for (mediaPlayer in mediaPlayers.values) { + for (mediaPlayer in MediaPlayerData.players()) { val controller = mediaPlayer.mediaViewController // When transitioning the view to gone, the view gets smaller, but the translation // Doesn't, let's add the translation @@ -448,7 +424,7 @@ class MediaCarouselController @Inject constructor( this.desiredLocation = desiredLocation this.desiredHostState = it currentlyExpanded = it.expansion > 0 - for (mediaPlayer in mediaPlayers.values) { + for (mediaPlayer in MediaPlayerData.players()) { if (animate) { mediaPlayer.mediaViewController.animatePendingStateChange( duration = duration, @@ -470,7 +446,7 @@ class MediaCarouselController @Inject constructor( } fun closeGuts() { - mediaPlayers.values.forEach { + MediaPlayerData.players().forEach { it.closeGuts(true) } } @@ -497,3 +473,50 @@ class MediaCarouselController @Inject constructor( } } } + +@VisibleForTesting +internal object MediaPlayerData { + private data class MediaSortKey( + val data: MediaData, + val updateTime: Long = 0, + val isPlaying: Boolean = false + ) + + private val comparator = + compareByDescending<MediaSortKey> { it.isPlaying } + .thenByDescending { it.data.isLocalSession } + .thenByDescending { !it.data.resumption } + .thenByDescending { it.updateTime } + + private val mediaPlayers = TreeMap<MediaSortKey, MediaControlPanel>(comparator) + private val mediaData: MutableMap<String, MediaSortKey> = mutableMapOf() + + fun addMediaPlayer(key: String, data: MediaData, player: MediaControlPanel) { + removeMediaPlayer(key) + val sortKey = MediaSortKey(data, System.currentTimeMillis(), player.isPlaying()) + mediaData.put(key, sortKey) + mediaPlayers.put(sortKey, player) + } + + fun getMediaPlayer(key: String, oldKey: String?): MediaControlPanel? { + // If the key was changed, update entry + oldKey?.let { + if (it != key) { + mediaData.remove(it)?.let { sortKey -> mediaData.put(key, sortKey) } + } + } + return mediaData.get(key)?.let { mediaPlayers.get(it) } + } + + fun removeMediaPlayer(key: String) = mediaData.remove(key)?.let { mediaPlayers.remove(it) } + + fun mediaData() = mediaData.entries.map { e -> Pair(e.key, e.value.data) } + + fun players() = mediaPlayers.values + + @VisibleForTesting + fun clear() { + mediaData.clear() + mediaPlayers.clear() + } +} diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt index dafc52ad8025..d6a02687c905 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt @@ -82,6 +82,10 @@ data class MediaData( */ var resumeAction: Runnable?, /** + * Local or remote playback + */ + var isLocalSession: Boolean = true, + /** * Indicates that this player is a resumption player (ie. It only shows a play actions which * will start the app and start playing). */ diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt index e77e499223aa..bff334e92366 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt @@ -31,6 +31,7 @@ import android.graphics.drawable.Drawable import android.graphics.drawable.Icon import android.media.MediaDescription import android.media.MediaMetadata +import android.media.session.MediaController import android.media.session.MediaSession import android.net.Uri import android.os.UserHandle @@ -56,6 +57,8 @@ import java.io.PrintWriter import java.util.concurrent.Executor import javax.inject.Inject import javax.inject.Singleton +import kotlin.collections.ArrayList +import kotlin.collections.LinkedHashMap // URI fields to try loading album art from private val ART_URIS = arrayOf( @@ -105,6 +108,17 @@ class MediaDataManager( private val listeners: MutableSet<Listener> = mutableSetOf() private val mediaEntries: LinkedHashMap<String, MediaData> = LinkedHashMap() + internal var appsBlockedFromResume: MutableSet<String> = Utils.getBlockedMediaApps(context) + set(value) { + // Update list + appsBlockedFromResume.clear() + appsBlockedFromResume.addAll(value) + + // Remove any existing resume players that are now blocked + appsBlockedFromResume.forEach { + removeAllForPackage(it) + } + } @Inject constructor( @@ -331,7 +345,8 @@ class MediaDataManager( ) { val token = sbn.notification.extras.getParcelable(Notification.EXTRA_MEDIA_SESSION) as MediaSession.Token? - val metadata = mediaControllerFactory.create(token).metadata + val mediaController = mediaControllerFactory.create(token) + val metadata = mediaController.metadata // Foreground and Background colors computed from album art val notif: Notification = sbn.notification @@ -426,6 +441,9 @@ class MediaDataManager( } } + val isLocalSession = mediaController.playbackInfo?.playbackType == + MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL ?: true + foregroundExecutor.execute { val resumeAction: Runnable? = mediaEntries[key]?.resumeAction val hasCheckedForResume = mediaEntries[key]?.hasCheckedForResume == true @@ -433,8 +451,8 @@ class MediaDataManager( onMediaDataLoaded(key, oldKey, MediaData(sbn.normalizedUserId, true, bgColor, app, smallIconDrawable, artist, song, artWorkIcon, actionIcons, actionsToShowCollapsed, sbn.packageName, token, notif.contentIntent, null, - active, resumeAction = resumeAction, notificationKey = key, - hasCheckedForResume = hasCheckedForResume)) + active, resumeAction = resumeAction, isLocalSession = isLocalSession, + notificationKey = key, hasCheckedForResume = hasCheckedForResume)) } } @@ -542,8 +560,9 @@ class MediaDataManager( fun onNotificationRemoved(key: String) { Assert.isMainThread() val removed = mediaEntries.remove(key) - if (useMediaResumption && removed?.resumeAction != null) { - if (DEBUG) Log.d(TAG, "Not removing $key because resumable") + if (useMediaResumption && removed?.resumeAction != null && + !isBlockedFromResume(removed?.packageName)) { + Log.d(TAG, "Not removing $key because resumable") // Move to resume key (aka package name) if that key doesn't already exist. val resumeAction = getResumeMediaAction(removed.resumeAction!!) val updated = removed.copy(token = null, actions = listOf(resumeAction), @@ -579,6 +598,13 @@ class MediaDataManager( } } + private fun isBlockedFromResume(packageName: String?): Boolean { + if (packageName == null) { + return true + } + return appsBlockedFromResume.contains(packageName) + } + fun setMediaResumptionEnabled(isEnabled: Boolean) { if (useMediaResumption == isEnabled) { return @@ -621,6 +647,7 @@ class MediaDataManager( println("listeners: $listeners") println("mediaEntries: $mediaEntries") println("useMediaResumption: $useMediaResumption") + println("appsBlockedFromResume: $appsBlockedFromResume") } } } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt index 4ec746fcb153..c41712c4cf10 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt @@ -52,6 +52,7 @@ class MediaResumeListener @Inject constructor( private var useMediaResumption: Boolean = Utils.useMediaResumption(context) private val resumeComponents: ConcurrentLinkedQueue<ComponentName> = ConcurrentLinkedQueue() + private var blockedApps: MutableSet<String> = Utils.getBlockedMediaApps(context) private lateinit var mediaDataManager: MediaDataManager @@ -114,6 +115,14 @@ class MediaResumeListener @Inject constructor( mediaDataManager.setMediaResumptionEnabled(useMediaResumption) } }, Settings.Secure.MEDIA_CONTROLS_RESUME) + + // Listen to changes in which apps are allowed to persist + tunerService.addTunable(object : TunerService.Tunable { + override fun onTuningChanged(key: String?, newValue: String?) { + blockedApps = Utils.getBlockedMediaApps(context) + mediaDataManager.appsBlockedFromResume = blockedApps + } + }, Settings.Secure.MEDIA_CONTROLS_RESUME_BLOCKED) } fun isResumptionEnabled() = useMediaResumption @@ -144,8 +153,10 @@ class MediaResumeListener @Inject constructor( } resumeComponents.forEach { - val browser = ResumeMediaBrowser(context, mediaBrowserCallback, it) - browser.findRecentMedia() + if (!blockedApps.contains(it.packageName)) { + val browser = ResumeMediaBrowser(context, mediaBrowserCallback, it) + browser.findRecentMedia() + } } } @@ -154,7 +165,8 @@ class MediaResumeListener @Inject constructor( // If this had been started from a resume state, disconnect now that it's live mediaBrowser?.disconnect() // If we don't have a resume action, check if we haven't already - if (data.resumeAction == null && !data.hasCheckedForResume) { + if (data.resumeAction == null && !data.hasCheckedForResume && + !blockedApps.contains(data.packageName)) { // TODO also check for a media button receiver intended for restarting (b/154127084) Log.d(TAG, "Checking for service component for " + data.packageName) val pm = context.packageManager diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java index fd653b4e8aa5..6c8a23ba96d1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java @@ -1,18 +1,20 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2020 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 + * 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. + * 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.statusbar.phone; +package com.android.systemui.navigationbar; import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT; import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN; @@ -21,6 +23,7 @@ import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; import static android.app.StatusBarManager.WindowType; import static android.app.StatusBarManager.WindowVisibleState; import static android.app.StatusBarManager.windowStateToString; +import static android.view.Display.DEFAULT_DISPLAY; import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; import static android.view.InsetsState.containsType; import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; @@ -78,17 +81,16 @@ import android.text.TextUtils; import android.util.Log; import android.view.Display; import android.view.Gravity; +import android.view.IWindowManager; import android.view.InsetsState.InternalInsetsType; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.Surface; import android.view.View; -import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.WindowInsetsController.Appearance; import android.view.WindowManager; -import android.view.WindowManager.LayoutParams; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener; @@ -102,6 +104,7 @@ import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.LatencyTracker; import com.android.internal.view.AppearanceRegion; +import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.accessibility.SystemActions; import com.android.systemui.assist.AssistHandleViewController; @@ -109,8 +112,12 @@ import com.android.systemui.assist.AssistManager; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.fragments.FragmentHostManager; -import com.android.systemui.fragments.FragmentHostManager.FragmentListener; import com.android.systemui.model.SysUiState; +import com.android.systemui.navigationbar.buttons.ButtonDispatcher; +import com.android.systemui.navigationbar.buttons.KeyButtonView; +import com.android.systemui.navigationbar.buttons.RotationContextButton; +import com.android.systemui.navigationbar.gestural.QuickswitchOrientedNavHandle; +import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.recents.Recents; @@ -123,29 +130,28 @@ import com.android.systemui.statusbar.CommandQueue.Callbacks; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; -import com.android.systemui.statusbar.phone.ContextualButton.ContextButtonListener; +import com.android.systemui.statusbar.phone.AutoHideController; +import com.android.systemui.statusbar.phone.BarTransitions; +import com.android.systemui.statusbar.phone.LightBarController; +import com.android.systemui.statusbar.phone.ShadeController; +import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; +import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; -import com.android.systemui.statusbar.policy.KeyButtonView; -import com.android.systemui.util.LifecycleFragment; -import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.List; import java.util.Locale; import java.util.Optional; import java.util.function.Consumer; -import javax.inject.Inject; - import dagger.Lazy; /** - * Fragment containing the NavigationBarFragment. Contains logic for what happens - * on clicks and view states of the nav bar. + * Contains logic for a navigation bar view. */ -public class NavigationBarFragment extends LifecycleFragment implements Callbacks, - NavigationModeController.ModeChangedListener, DisplayManager.DisplayListener { +public class NavigationBar implements View.OnAttachStateChangeListener, + Callbacks, NavigationModeController.ModeChangedListener, DisplayManager.DisplayListener { public static final String TAG = "NavigationBar"; private static final boolean DEBUG = false; @@ -158,35 +164,41 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200; private static final long AUTODIM_TIMEOUT_MS = 2250; + private final Context mContext; + private final WindowManager mWindowManager; + private final AccessibilityManager mAccessibilityManager; private final AccessibilityManagerWrapper mAccessibilityManagerWrapper; - protected final AssistManager mAssistManager; - private SysUiState mSysUiFlagsContainer; - private final MetricsLogger mMetricsLogger; private final DeviceProvisionedController mDeviceProvisionedController; private final StatusBarStateController mStatusBarStateController; + private final MetricsLogger mMetricsLogger; + private final Lazy<AssistManager> mAssistManagerLazy; + private final SysUiState mSysUiFlagsContainer; + private final Lazy<StatusBar> mStatusBarLazy; + private final ShadeController mShadeController; + private final NotificationRemoteInputManager mNotificationRemoteInputManager; + private final OverviewProxyService mOverviewProxyService; private final NavigationModeController mNavigationModeController; + private final BroadcastDispatcher mBroadcastDispatcher; + private final CommandQueue mCommandQueue; + private final Divider mDivider; + private final Optional<Recents> mRecentsOptional; + private final SystemActions mSystemActions; + private final Handler mHandler; + private final UiEventLogger mUiEventLogger; - protected NavigationBarView mNavigationBarView = null; + private Bundle mSavedState; + private NavigationBarView mNavigationBarView = null; private @WindowVisibleState int mNavigationBarWindowState = WINDOW_STATE_SHOWING; private int mNavigationIconHints = 0; private @TransitionMode int mNavigationBarMode; - private AccessibilityManager mAccessibilityManager; private ContentResolver mContentResolver; private boolean mAssistantAvailable; private int mDisabledFlags1; private int mDisabledFlags2; - private final Lazy<StatusBar> mStatusBarLazy; - private final ShadeController mShadeController; - private final NotificationRemoteInputManager mNotificationRemoteInputManager; - private final Divider mDivider; - private final Optional<Recents> mRecentsOptional; - private WindowManager mWindowManager; - private final CommandQueue mCommandQueue; private long mLastLockToAppLongPress; - private final SystemActions mSystemActions; private Locale mLocale; private int mLayoutDirection; @@ -202,10 +214,6 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback private LightBarController mLightBarController; private AutoHideController mAutoHideController; - private OverviewProxyService mOverviewProxyService; - - private final BroadcastDispatcher mBroadcastDispatcher; - @VisibleForTesting public int mDisplayId; private boolean mIsOnDefaultDisplay; @@ -226,7 +234,6 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback private int mStartingQuickSwitchRotation = -1; private int mCurrentRotation; private ViewTreeObserver.OnGlobalLayoutListener mOrientationHandleGlobalLayoutListener; - private UiEventLogger mUiEventLogger; private boolean mShowOrientedHandleForImmersiveMode; @com.android.internal.annotations.VisibleForTesting @@ -251,7 +258,6 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback @Nullable private AssistHandleViewController mAssistHandlerViewController; - private final Handler mHandler; private final AutoHideUiElement mAutoHideUiElement = new AutoHideUiElement() { @Override @@ -307,7 +313,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback @Override public void startAssistant(Bundle bundle) { - mAssistManager.startAssist(bundle); + mAssistManagerLazy.get().startAssist(bundle); } @Override @@ -360,7 +366,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback new Handler(Looper.getMainLooper())) { @Override public void onChange(boolean selfChange, Uri uri) { - boolean available = mAssistManager + boolean available = mAssistManagerLazy.get() .getAssistInfoForUser(UserHandle.USER_CURRENT) != null; if (mAssistantAvailable != available) { sendAssistantAvailability(available); @@ -369,34 +375,6 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback } }; - private static class NavBarViewAttachedListener implements View.OnAttachStateChangeListener { - private NavigationBarFragment mFragment; - private FragmentListener mListener; - - NavBarViewAttachedListener(NavigationBarFragment fragment, FragmentListener listener) { - mFragment = fragment; - mListener = listener; - } - - @Override - public void onViewAttachedToWindow(View v) { - final FragmentHostManager fragmentHost = FragmentHostManager.get(v); - fragmentHost.getFragmentManager().beginTransaction() - .replace(R.id.navigation_bar_frame, mFragment, TAG) - .commit(); - fragmentHost.addTagListener(TAG, mListener); - mFragment = null; - } - - @Override - public void onViewDetachedFromWindow(View v) { - final FragmentHostManager fragmentHost = FragmentHostManager.get(v); - fragmentHost.removeTagListener(TAG, mListener); - FragmentHostManager.removeAndDestroy(v); - v.removeOnAttachStateChangeListener(this); - } - } - private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener = new DeviceConfig.OnPropertiesChangedListener() { @Override @@ -416,10 +394,14 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback } }; - @Inject - public NavigationBarFragment(AccessibilityManagerWrapper accessibilityManagerWrapper, - DeviceProvisionedController deviceProvisionedController, MetricsLogger metricsLogger, - AssistManager assistManager, OverviewProxyService overviewProxyService, + public NavigationBar(Context context, + WindowManager windowManager, + Lazy<AssistManager> assistManagerLazy, + AccessibilityManager accessibilityManager, + AccessibilityManagerWrapper accessibilityManagerWrapper, + DeviceProvisionedController deviceProvisionedController, + MetricsLogger metricsLogger, + OverviewProxyService overviewProxyService, NavigationModeController navigationModeController, StatusBarStateController statusBarStateController, SysUiState sysUiFlagsContainer, @@ -431,16 +413,18 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback SystemActions systemActions, @Main Handler mainHandler, UiEventLogger uiEventLogger) { + mContext = context; + mWindowManager = windowManager; + mAccessibilityManager = accessibilityManager; mAccessibilityManagerWrapper = accessibilityManagerWrapper; mDeviceProvisionedController = deviceProvisionedController; mStatusBarStateController = statusBarStateController; mMetricsLogger = metricsLogger; - mAssistManager = assistManager; + mAssistManagerLazy = assistManagerLazy; mSysUiFlagsContainer = sysUiFlagsContainer; mStatusBarLazy = statusBarLazy; mShadeController = shadeController; mNotificationRemoteInputManager = notificationRemoteInputManager; - mAssistantAvailable = mAssistManager.getAssistInfoForUser(UserHandle.USER_CURRENT) != null; mOverviewProxyService = overviewProxyService; mNavigationModeController = navigationModeController; mNavBarMode = navigationModeController.addListener(this); @@ -453,25 +437,53 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback mUiEventLogger = uiEventLogger; } - // ----- Fragment Lifecycle Callbacks ----- + public View getView() { + return mNavigationBarView; + } - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mCommandQueue.observe(getLifecycle(), this); - mWindowManager = getContext().getSystemService(WindowManager.class); - mAccessibilityManager = getContext().getSystemService(AccessibilityManager.class); - mContentResolver = getContext().getContentResolver(); + public View createView(Bundle savedState) { + WindowManager.LayoutParams lp = new WindowManager.LayoutParams( + WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.TYPE_NAVIGATION_BAR, + WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH + | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH + | WindowManager.LayoutParams.FLAG_SLIPPERY, + PixelFormat.TRANSLUCENT); + lp.token = new Binder(); + lp.setTitle("NavigationBar" + mContext.getDisplayId()); + lp.accessibilityTitle = mContext.getString(R.string.nav_bar); + lp.windowAnimations = 0; + lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC; + + LayoutInflater layoutInflater = LayoutInflater.from(mContext); + NavigationBarFrame frame = (NavigationBarFrame) layoutInflater.inflate( + R.layout.navigation_bar_window, null); + View barView = layoutInflater.inflate(R.layout.navigation_bar, frame); + barView.addOnAttachStateChangeListener(this); + + if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + barView); + mContext.getSystemService(WindowManager.class).addView(frame, lp); + mDisplayId = mContext.getDisplayId(); + mIsOnDefaultDisplay = mDisplayId == DEFAULT_DISPLAY; + + mCommandQueue.addCallback(this); + mAssistantAvailable = mAssistManagerLazy.get() + .getAssistInfoForUser(UserHandle.USER_CURRENT) != null; + mContentResolver = mContext.getContentResolver(); mContentResolver.registerContentObserver( Settings.Secure.getUriFor(Settings.Secure.ASSISTANT), false /* notifyForDescendants */, mAssistContentObserver, UserHandle.USER_ALL); - if (savedInstanceState != null) { - mDisabledFlags1 = savedInstanceState.getInt(EXTRA_DISABLE_STATE, 0); - mDisabledFlags2 = savedInstanceState.getInt(EXTRA_DISABLE2_STATE, 0); - mAppearance = savedInstanceState.getInt(EXTRA_APPEARANCE, 0); - mTransientShown = savedInstanceState.getBoolean(EXTRA_TRANSIENT_STATE, false); + if (savedState != null) { + mDisabledFlags1 = savedState.getInt(EXTRA_DISABLE_STATE, 0); + mDisabledFlags2 = savedState.getInt(EXTRA_DISABLE2_STATE, 0); + mAppearance = savedState.getInt(EXTRA_APPEARANCE, 0); + mTransientShown = savedState.getBoolean(EXTRA_TRANSIENT_STATE, false); } + mSavedState = savedState; mAccessibilityManagerWrapper.addCallback(mAccessibilityListener); // Respect the latest disabled-flags. @@ -486,12 +498,16 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback mIsCurrentUserSetup = mDeviceProvisionedController.isCurrentUserSetup(); mDeviceProvisionedController.addCallback(mUserSetupListener); + + return barView; } - @Override - public void onDestroy() { - super.onDestroy(); + public void destroyView() { + mCommandQueue.removeCallback(this); + mContext.getSystemService(WindowManager.class).removeViewImmediate( + mNavigationBarView.getRootView()); mNavigationModeController.removeListener(this); + mAccessibilityManagerWrapper.removeCallback(mAccessibilityListener); mContentResolver.unregisterContentObserver(mAssistContentObserver); mDeviceProvisionedController.removeCallback(mUserSetupListener); @@ -500,28 +516,15 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback } @Override - public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, - Bundle savedInstanceState) { - return inflater.inflate(R.layout.navigation_bar, container, false); - } - - @Override - public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - mNavigationBarView = (NavigationBarView) view; - final Display display = view.getDisplay(); - // It may not have display when running unit test. - if (display != null) { - mDisplayId = display.getDisplayId(); - mIsOnDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY; - } - + public void onViewAttachedToWindow(View v) { + final Display display = v.getDisplay(); + mNavigationBarView = v.findViewById(R.id.navigation_bar_view); mNavigationBarView.setComponents(mStatusBarLazy.get().getPanelController()); mNavigationBarView.setDisabledFlags(mDisabledFlags1); mNavigationBarView.setOnVerticalChangedListener(this::onVerticalChanged); mNavigationBarView.setOnTouchListener(this::onNavigationTouch); - if (savedInstanceState != null) { - mNavigationBarView.getLightTransitionsController().restoreState(savedInstanceState); + if (mSavedState != null) { + mNavigationBarView.getLightTransitionsController().restoreState(mSavedState); } mNavigationBarView.setNavigationIconHints(mNavigationIconHints); mNavigationBarView.setWindowVisible(isNavBarWindowVisible()); @@ -561,11 +564,32 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback } initSecondaryHomeHandleForRotation(); + + // Unfortunately, we still need it because status bar needs LightBarController + // before notifications creation. We cannot directly use getLightBarController() + // from NavigationBarFragment directly. + LightBarController lightBarController = mIsOnDefaultDisplay + ? Dependency.get(LightBarController.class) + : new LightBarController(mContext, + Dependency.get(DarkIconDispatcher.class), + Dependency.get(BatteryController.class), + Dependency.get(NavigationModeController.class)); + setLightBarController(lightBarController); + + // TODO(b/118592525): to support multi-display, we start to add something which is + // per-display, while others may be global. I think it's time to + // add a new class maybe named DisplayDependency to solve + // per-display Dependency problem. + AutoHideController autoHideController = mIsOnDefaultDisplay + ? Dependency.get(AutoHideController.class) + : new AutoHideController(mContext, mHandler, + Dependency.get(IWindowManager.class)); + setAutoHideController(autoHideController); + restoreAppearanceAndTransientState(); } @Override - public void onDestroyView() { - super.onDestroyView(); + public void onViewDetachedFromWindow(View v) { if (mNavigationBarView != null) { if (mIsOnDefaultDisplay) { mNavigationBarView.getBarTransitions() @@ -573,13 +597,13 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback mAssistHandlerViewController = null; } mNavigationBarView.getBarTransitions().destroy(); - mNavigationBarView.getLightTransitionsController().destroy(getContext()); + mNavigationBarView.getLightTransitionsController().destroy(mContext); } mOverviewProxyService.removeCallback(mOverviewProxyListener); mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver); if (mOrientationHandle != null) { resetSecondaryHandle(); - getContext().getSystemService(DisplayManager.class).unregisterDisplayListener(this); + mContext.getSystemService(DisplayManager.class).unregisterDisplayListener(this); getBarTransitions().removeDarkIntensityListener(mOrientationHandleIntensityListener); mWindowManager.removeView(mOrientationHandle); mOrientationHandle.getViewTreeObserver().removeOnGlobalLayoutListener( @@ -590,9 +614,8 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback mOrientationHandle = null; } - @Override + // TODO: Remove this when we update nav bar recreation public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); outState.putInt(EXTRA_DISABLE_STATE, mDisabledFlags1); outState.putInt(EXTRA_DISABLE2_STATE, mDisabledFlags2); outState.putInt(EXTRA_APPEARANCE, mAppearance); @@ -602,10 +625,11 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback } } - @Override + /** + * Called when a non-reloading configuration change happens and we need to update. + */ public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - final Locale locale = getContext().getResources().getConfiguration().locale; + final Locale locale = mContext.getResources().getConfiguration().locale; final int ld = TextUtils.getLayoutDirectionFromLocale(locale); if (!locale.equals(mLocale) || ld != mLayoutDirection) { if (DEBUG) { @@ -625,10 +649,10 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback return; } - getContext().getSystemService(DisplayManager.class) + mContext.getSystemService(DisplayManager.class) .registerDisplayListener(this, new Handler(Looper.getMainLooper())); - mOrientationHandle = new QuickswitchOrientedNavHandle(getContext()); + mOrientationHandle = new QuickswitchOrientedNavHandle(mContext); mOrientationHandle.setId(R.id.secondary_home_handle); getBarTransitions().addDarkIntensityListener(mOrientationHandleIntensityListener); @@ -640,7 +664,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH | WindowManager.LayoutParams.FLAG_SLIPPERY, PixelFormat.TRANSLUCENT); - mOrientationParams.setTitle("SecondaryHomeHandle" + getContext().getDisplayId()); + mOrientationParams.setTitle("SecondaryHomeHandle" + mContext.getDisplayId()); mOrientationParams.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION; mWindowManager.addView(mOrientationHandle, mOrientationParams); mOrientationHandle.setVisibility(View.GONE); @@ -729,23 +753,20 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback return delta; } - @Override - public void dump(String prefix, FileDescriptor fd, PrintWriter pw, String[] args) { + public void dump(PrintWriter pw) { + pw.println("NavigationBar (displayId=" + mDisplayId + "):"); + pw.println(" mStartingQuickSwitchRotation=" + mStartingQuickSwitchRotation); + pw.println(" mCurrentRotation=" + mCurrentRotation); + if (mNavigationBarView != null) { - pw.print(" mNavigationBarWindowState="); - pw.println(windowStateToString(mNavigationBarWindowState)); - pw.print(" mNavigationBarMode="); - pw.println(BarTransitions.modeToString(mNavigationBarMode)); + pw.println(" mNavigationBarWindowState=" + + windowStateToString(mNavigationBarWindowState)); + pw.println(" mNavigationBarMode=" + + BarTransitions.modeToString(mNavigationBarMode)); dumpBarTransitions(pw, "mNavigationBarView", mNavigationBarView.getBarTransitions()); - } - - pw.print(" mStartingQuickSwitchRotation=" + mStartingQuickSwitchRotation); - pw.print(" mCurrentRotation=" + mCurrentRotation); - pw.print(" mNavigationBarView="); - if (mNavigationBarView == null) { - pw.println("null"); + mNavigationBarView.dump(pw); } else { - mNavigationBarView.dump(fd, pw, args); + pw.print(" mNavigationBarView=null"); } } @@ -834,15 +855,18 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback rotationButtonController.onRotationProposal(rotation, winRotation, isValid); } - /** Restores the appearance and the transient saved state to {@link NavigationBarFragment}. */ + /** Restores the appearance and the transient saved state to {@link NavigationBar}. */ public void restoreAppearanceAndTransientState() { final int barMode = barMode(mTransientShown, mAppearance); mNavigationBarMode = barMode; checkNavBarModes(); - mAutoHideController.touchAutoHide(); - - mLightBarController.onNavigationBarAppearanceChanged(mAppearance, true /* nbModeChanged */, - barMode, false /* navbarColorManagedByIme */); + if (mAutoHideController != null) { + mAutoHideController.touchAutoHide(); + } + if (mLightBarController != null) { + mLightBarController.onNavigationBarAppearanceChanged(mAppearance, + true /* nbModeChanged */, barMode, false /* navbarColorManagedByIme */); + } } @Override @@ -859,8 +883,10 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback } nbModeChanged = updateBarMode(barMode(mTransientShown, appearance)); } - mLightBarController.onNavigationBarAppearanceChanged(appearance, nbModeChanged, - mNavigationBarMode, navbarColorManagedByIme); + if (mLightBarController != null) { + mLightBarController.onNavigationBarAppearanceChanged(appearance, nbModeChanged, + mNavigationBarMode, navbarColorManagedByIme); + } } @Override @@ -903,7 +929,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback mNavigationBarView.onTransientStateChanged(mTransientShown); } final int barMode = barMode(mTransientShown, mAppearance); - if (updateBarMode(barMode)) { + if (updateBarMode(barMode) && mLightBarController != null) { mLightBarController.onNavigationBarModeChanged(barMode); } } @@ -917,7 +943,9 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback } mNavigationBarMode = barMode; checkNavBarModes(); - mAutoHideController.touchAutoHide(); + if (mAutoHideController != null) { + mAutoHideController.touchAutoHide(); + } return true; } return false; @@ -1053,7 +1081,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback case MotionEvent.ACTION_DOWN: mHomeBlockedThisTouch = false; TelecomManager telecomManager = - getContext().getSystemService(TelecomManager.class); + mContext.getSystemService(TelecomManager.class); if (telecomManager != null && telecomManager.isRinging()) { if (mStatusBarLazy.get().isKeyguardShowing()) { Log.i(TAG, "Ignoring HOME; there's a ringing incoming call. " + @@ -1076,7 +1104,9 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback } private boolean onNavigationTouch(View v, MotionEvent event) { - mAutoHideController.checkUserAutoHide(event); + if (mAutoHideController != null) { + mAutoHideController.checkUserAutoHide(event); + } return false; } @@ -1094,7 +1124,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback Bundle args = new Bundle(); args.putInt( AssistManager.INVOCATION_TYPE_KEY, AssistManager.INVOCATION_HOME_BUTTON_LONG_PRESS); - mAssistManager.startAssist(args); + mAssistManagerLazy.get().startAssist(args); mStatusBarLazy.get().awakenDreams(); if (mNavigationBarView != null) { @@ -1120,8 +1150,8 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback } private void onRecentsClick(View v) { - if (LatencyTracker.isEnabled(getContext())) { - LatencyTracker.getInstance(getContext()).onActionStart( + if (LatencyTracker.isEnabled(mContext)) { + LatencyTracker.getInstance(mContext).onActionStart( LatencyTracker.ACTION_TOGGLE_RECENTS); } mStatusBarLazy.get().awakenDreams(); @@ -1215,7 +1245,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback } private boolean onLongPressRecents() { - if (mRecentsOptional.isPresent() || !ActivityTaskManager.supportsMultiWindow(getContext()) + if (mRecentsOptional.isPresent() || !ActivityTaskManager.supportsMultiWindow(mContext) || !mDivider.getView().getSnapAlgorithm().isSplitScreenFeasible() || ActivityManager.isLowRamDeviceStatic() // If we are connected to the overview service, then disable the recents button @@ -1230,7 +1260,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback private void onAccessibilityClick(View v) { final Display display = v.getDisplay(); mAccessibilityManager.notifyAccessibilityButtonClicked( - display != null ? display.getDisplayId() : Display.DEFAULT_DISPLAY); + display != null ? display.getDisplayId() : DEFAULT_DISPLAY); } private boolean onAccessibilityLongClick(View v) { @@ -1238,7 +1268,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); final String chooserClassName = AccessibilityButtonChooserActivity.class.getName(); intent.setClassName(CHOOSER_PACKAGE_NAME, chooserClassName); - v.getContext().startActivityAsUser(intent, UserHandle.CURRENT); + mContext.startActivityAsUser(intent, UserHandle.CURRENT); return true; } @@ -1335,7 +1365,10 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback public void setLightBarController(LightBarController lightBarController) { mLightBarController = lightBarController; - mLightBarController.setNavigationBar(mNavigationBarView.getLightTransitionsController()); + if (mLightBarController != null) { + mLightBarController.setNavigationBar( + mNavigationBarView.getLightTransitionsController()); + } } /** Sets {@link AutoHideController} to the navigation bar. */ @@ -1381,17 +1414,6 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback if (!canShowSecondaryHandle()) { resetSecondaryHandle(); } - - // Workaround for b/132825155, for secondary users, we currently don't receive configuration - // changes on overlay package change since SystemUI runs for the system user. In this case, - // trigger a new configuration change to ensure that the nav bar is updated in the same way. - int userId = ActivityManagerWrapper.getInstance().getCurrentUserId(); - if (userId != UserHandle.USER_SYSTEM) { - mHandler.post(() -> { - FragmentHostManager fragmentHost = FragmentHostManager.get(mNavigationBarView); - fragmentHost.reloadFragments(); - }); - } } public void disableAnimationsDuringHide(long delay) { @@ -1442,7 +1464,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback return; } - int rotation = getContext().getResources().getConfiguration() + int rotation = mContext.getResources().getConfiguration() .windowConfiguration.getRotation(); if (rotation != mCurrentRotation) { mCurrentRotation = rotation; @@ -1480,37 +1502,6 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback } }; - public static View create(Context context, FragmentListener listener) { - WindowManager.LayoutParams lp = new WindowManager.LayoutParams( - LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, - WindowManager.LayoutParams.TYPE_NAVIGATION_BAR, - WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING - | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL - | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH - | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH - | WindowManager.LayoutParams.FLAG_SLIPPERY, - PixelFormat.TRANSLUCENT); - lp.token = new Binder(); - lp.setTitle("NavigationBar" + context.getDisplayId()); - lp.accessibilityTitle = context.getString(R.string.nav_bar); - lp.windowAnimations = 0; - lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC; - - View navigationBarView = LayoutInflater.from(context).inflate( - R.layout.navigation_bar_window, null); - - if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + navigationBarView); - if (navigationBarView == null) return null; - - NavigationBarFragment fragment = FragmentHostManager.get(navigationBarView) - .create(NavigationBarFragment.class); - navigationBarView.addOnAttachStateChangeListener(new NavBarViewAttachedListener(fragment, - listener)); - context.getSystemService(WindowManager.class).addView(navigationBarView, lp); - return navigationBarView; - } - @VisibleForTesting int getNavigationIconHints() { return mNavigationIconHints; diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java new file mode 100644 index 000000000000..73cdde8a0c91 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java @@ -0,0 +1,396 @@ +/* + * Copyright (C) 2020 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.navigationbar; + +import static android.view.Display.DEFAULT_DISPLAY; + +import android.content.Context; +import android.content.pm.ActivityInfo; +import android.content.res.Configuration; +import android.hardware.display.DisplayManager; +import android.os.Bundle; +import android.os.Handler; +import android.os.RemoteException; +import android.os.UserHandle; +import android.util.Log; +import android.util.SparseArray; +import android.view.Display; +import android.view.IWindowManager; +import android.view.View; +import android.view.WindowManager; +import android.view.WindowManagerGlobal; +import android.view.accessibility.AccessibilityManager; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.UiEventLogger; +import com.android.internal.statusbar.RegisterStatusBarResult; +import com.android.settingslib.applications.InterestingConfigChanges; +import com.android.systemui.Dumpable; +import com.android.systemui.accessibility.SystemActions; +import com.android.systemui.assist.AssistHandleViewController; +import com.android.systemui.assist.AssistManager; +import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.model.SysUiState; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.recents.OverviewProxyService; +import com.android.systemui.recents.Recents; +import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.stackdivider.Divider; +import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.CommandQueue.Callbacks; +import com.android.systemui.statusbar.NotificationRemoteInputManager; +import com.android.systemui.statusbar.phone.BarTransitions.TransitionMode; +import com.android.systemui.statusbar.phone.ShadeController; +import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; +import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.DeviceProvisionedController; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.Optional; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import dagger.Lazy; + + +/** A controller to handle navigation bars. */ +@Singleton +public class NavigationBarController implements Callbacks, + ConfigurationController.ConfigurationListener, + NavigationModeController.ModeChangedListener, Dumpable { + + private static final String TAG = NavigationBarController.class.getSimpleName(); + + private final Context mContext; + private final WindowManager mWindowManager; + private final Lazy<AssistManager> mAssistManagerLazy; + private final AccessibilityManager mAccessibilityManager; + private final AccessibilityManagerWrapper mAccessibilityManagerWrapper; + private final DeviceProvisionedController mDeviceProvisionedController; + private final MetricsLogger mMetricsLogger; + private final OverviewProxyService mOverviewProxyService; + private final NavigationModeController mNavigationModeController; + private final StatusBarStateController mStatusBarStateController; + private final SysUiState mSysUiFlagsContainer; + private final BroadcastDispatcher mBroadcastDispatcher; + private final CommandQueue mCommandQueue; + private final Divider mDivider; + private final Optional<Recents> mRecentsOptional; + private final Lazy<StatusBar> mStatusBarLazy; + private final ShadeController mShadeController; + private final NotificationRemoteInputManager mNotificationRemoteInputManager; + private final SystemActions mSystemActions; + private final UiEventLogger mUiEventLogger; + private final Handler mHandler; + private final DisplayManager mDisplayManager; + + /** A displayId - nav bar maps. */ + @VisibleForTesting + SparseArray<NavigationBar> mNavigationBars = new SparseArray<>(); + + // Tracks config changes that will actually recreate the nav bar + private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges( + ActivityInfo.CONFIG_FONT_SCALE | ActivityInfo.CONFIG_LOCALE + | ActivityInfo.CONFIG_SCREEN_LAYOUT | ActivityInfo.CONFIG_ASSETS_PATHS + | ActivityInfo.CONFIG_UI_MODE); + + @Inject + public NavigationBarController(Context context, + WindowManager windowManager, + Lazy<AssistManager> assistManagerLazy, + AccessibilityManager accessibilityManager, + AccessibilityManagerWrapper accessibilityManagerWrapper, + DeviceProvisionedController deviceProvisionedController, + MetricsLogger metricsLogger, + OverviewProxyService overviewProxyService, + NavigationModeController navigationModeController, + StatusBarStateController statusBarStateController, + SysUiState sysUiFlagsContainer, + BroadcastDispatcher broadcastDispatcher, + CommandQueue commandQueue, + Divider divider, + Optional<Recents> recentsOptional, + Lazy<StatusBar> statusBarLazy, + ShadeController shadeController, + NotificationRemoteInputManager notificationRemoteInputManager, + SystemActions systemActions, + @Main Handler mainHandler, + UiEventLogger uiEventLogger, + ConfigurationController configurationController) { + mContext = context; + mWindowManager = windowManager; + mAssistManagerLazy = assistManagerLazy; + mAccessibilityManager = accessibilityManager; + mAccessibilityManagerWrapper = accessibilityManagerWrapper; + mDeviceProvisionedController = deviceProvisionedController; + mMetricsLogger = metricsLogger; + mOverviewProxyService = overviewProxyService; + mNavigationModeController = navigationModeController; + mStatusBarStateController = statusBarStateController; + mSysUiFlagsContainer = sysUiFlagsContainer; + mBroadcastDispatcher = broadcastDispatcher; + mCommandQueue = commandQueue; + mDivider = divider; + mRecentsOptional = recentsOptional; + mStatusBarLazy = statusBarLazy; + mShadeController = shadeController; + mNotificationRemoteInputManager = notificationRemoteInputManager; + mSystemActions = systemActions; + mUiEventLogger = uiEventLogger; + mHandler = mainHandler; + mDisplayManager = mContext.getSystemService(DisplayManager.class); + commandQueue.addCallback(this); + configurationController.addCallback(this); + mConfigChanges.applyNewConfig(mContext.getResources()); + } + + @Override + public void onConfigChanged(Configuration newConfig) { + if (mConfigChanges.applyNewConfig(mContext.getResources())) { + for (int i = 0; i < mNavigationBars.size(); i++) { + recreateNavigationBar(mNavigationBars.keyAt(i)); + } + } else { + for (int i = 0; i < mNavigationBars.size(); i++) { + mNavigationBars.get(i).onConfigurationChanged(newConfig); + } + } + } + + @Override + public void onNavigationModeChanged(int mode) { + // Workaround for b/132825155, for secondary users, we currently don't receive configuration + // changes on overlay package change since SystemUI runs for the system user. In this case, + // trigger a new configuration change to ensure that the nav bar is updated in the same way. + int userId = ActivityManagerWrapper.getInstance().getCurrentUserId(); + if (userId != UserHandle.USER_SYSTEM) { + mHandler.post(() -> { + for (int i = 0; i < mNavigationBars.size(); i++) { + recreateNavigationBar(mNavigationBars.keyAt(i)); + } + }); + } + } + + @Override + public void onDisplayRemoved(int displayId) { + removeNavigationBar(displayId); + } + + @Override + public void onDisplayReady(int displayId) { + Display display = mDisplayManager.getDisplay(displayId); + createNavigationBar(display, null /* savedState */, null /* result */); + } + + /** + * Recreates the navigation bar for the given display. + */ + private void recreateNavigationBar(int displayId) { + // TODO: Improve this flow so that we don't need to create a new nav bar but just + // the view + Bundle savedState = new Bundle(); + NavigationBar bar = mNavigationBars.get(displayId); + if (bar != null) { + bar.onSaveInstanceState(savedState); + } + removeNavigationBar(displayId); + createNavigationBar(mDisplayManager.getDisplay(displayId), savedState, null /* result */); + } + + // TODO(b/117478341): I use {@code includeDefaultDisplay} to make this method compatible to + // CarStatusBar because they have their own nav bar. Think about a better way for it. + /** + * Creates navigation bars when car/status bar initializes. + * + * @param includeDefaultDisplay {@code true} to create navigation bar on default display. + */ + public void createNavigationBars(final boolean includeDefaultDisplay, + RegisterStatusBarResult result) { + Display[] displays = mDisplayManager.getDisplays(); + for (Display display : displays) { + if (includeDefaultDisplay || display.getDisplayId() != DEFAULT_DISPLAY) { + createNavigationBar(display, null /* savedState */, result); + } + } + } + + /** + * Adds a navigation bar on default display or an external display if the display supports + * system decorations. + * + * @param display the display to add navigation bar on. + */ + @VisibleForTesting + void createNavigationBar(Display display, Bundle savedState, RegisterStatusBarResult result) { + if (display == null) { + return; + } + + final int displayId = display.getDisplayId(); + final boolean isOnDefaultDisplay = displayId == DEFAULT_DISPLAY; + final IWindowManager wms = WindowManagerGlobal.getWindowManagerService(); + + try { + if (!wms.hasNavigationBar(displayId)) { + return; + } + } catch (RemoteException e) { + // Cannot get wms, just return with warning message. + Log.w(TAG, "Cannot get WindowManager."); + return; + } + final Context context = isOnDefaultDisplay + ? mContext + : mContext.createDisplayContext(display); + NavigationBar navBar = new NavigationBar(context, + mWindowManager, + mAssistManagerLazy, + mAccessibilityManager, + mAccessibilityManagerWrapper, + mDeviceProvisionedController, + mMetricsLogger, + mOverviewProxyService, + mNavigationModeController, + mStatusBarStateController, + mSysUiFlagsContainer, + mBroadcastDispatcher, + mCommandQueue, + mDivider, + mRecentsOptional, + mStatusBarLazy, + mShadeController, + mNotificationRemoteInputManager, + mSystemActions, + mHandler, + mUiEventLogger); + + View navigationBarView = navBar.createView(savedState); + navigationBarView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { + @Override + public void onViewAttachedToWindow(View v) { + mNavigationBars.put(displayId, navBar); + + if (result != null) { + navBar.setImeWindowStatus(display.getDisplayId(), result.mImeToken, + result.mImeWindowVis, result.mImeBackDisposition, + result.mShowImeSwitcher); + } + } + + @Override + public void onViewDetachedFromWindow(View v) { + v.removeOnAttachStateChangeListener(this); + } + }); + } + + private void removeNavigationBar(int displayId) { + NavigationBar navBar = mNavigationBars.get(displayId); + if (navBar != null) { + navBar.setAutoHideController(/* autoHideController */ null); + navBar.destroyView(); + mNavigationBars.remove(displayId); + } + } + + /** @see NavigationBar#checkNavBarModes() */ + public void checkNavBarModes(int displayId) { + NavigationBar navBar = mNavigationBars.get(displayId); + if (navBar != null) { + navBar.checkNavBarModes(); + } + } + + /** @see NavigationBar#finishBarAnimations() */ + public void finishBarAnimations(int displayId) { + NavigationBar navBar = mNavigationBars.get(displayId); + if (navBar != null) { + navBar.finishBarAnimations(); + } + } + + /** @see NavigationBar#touchAutoDim() */ + public void touchAutoDim(int displayId) { + NavigationBar navBar = mNavigationBars.get(displayId); + if (navBar != null) { + navBar.touchAutoDim(); + } + } + + /** @see NavigationBar#transitionTo(int, boolean) */ + public void transitionTo(int displayId, @TransitionMode int barMode, boolean animate) { + NavigationBar navBar = mNavigationBars.get(displayId); + if (navBar != null) { + navBar.transitionTo(barMode, animate); + } + } + + /** @see NavigationBar#disableAnimationsDuringHide(long) */ + public void disableAnimationsDuringHide(int displayId, long delay) { + NavigationBar navBar = mNavigationBars.get(displayId); + if (navBar != null) { + navBar.disableAnimationsDuringHide(delay); + } + } + + /** @return {@link NavigationBarView} on the default display. */ + public @Nullable NavigationBarView getDefaultNavigationBarView() { + return getNavigationBarView(DEFAULT_DISPLAY); + } + + /** + * @param displayId the ID of display which Navigation bar is on + * @return {@link NavigationBarView} on the display with {@code displayId}. + * {@code null} if no navigation bar on that display. + */ + public @Nullable NavigationBarView getNavigationBarView(int displayId) { + NavigationBar navBar = mNavigationBars.get(displayId); + return (navBar == null) ? null : (NavigationBarView) navBar.getView(); + } + + /** @return {@link NavigationBar} on the default display. */ + @Nullable + public NavigationBar getDefaultNavigationBar() { + return mNavigationBars.get(DEFAULT_DISPLAY); + } + + /** @return {@link AssistHandleViewController} (only on the default display). */ + @Nullable + public AssistHandleViewController getAssistHandlerViewController() { + NavigationBar navBar = getDefaultNavigationBar(); + return navBar == null ? null : navBar.getAssistHandlerViewController(); + } + + @Override + public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { + for (int i = 0; i < mNavigationBars.size(); i++) { + if (i > 0) { + pw.println(); + } + mNavigationBars.get(i).dump(pw); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFrame.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarFrame.java index 741f7839f455..6c531d8233f1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFrame.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarFrame.java @@ -1,18 +1,20 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2020 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 + * 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. + * 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.statusbar.phone; +package com.android.systemui.navigationbar; import static android.view.MotionEvent.ACTION_OUTSIDE; @@ -24,7 +26,7 @@ import android.util.AttributeSet; import android.view.MotionEvent; import android.widget.FrameLayout; -import com.android.systemui.statusbar.policy.DeadZone; +import com.android.systemui.navigationbar.buttons.DeadZone; public class NavigationBarFrame extends FrameLayout { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java index 4337e20c0a39..27074606d251 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarInflaterView.java @@ -1,18 +1,20 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2020 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 + * 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. + * 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.statusbar.phone; +package com.android.systemui.navigationbar; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; @@ -35,10 +37,12 @@ import android.widget.Space; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.Dependency; import com.android.systemui.R; +import com.android.systemui.navigationbar.buttons.ButtonDispatcher; +import com.android.systemui.navigationbar.buttons.KeyButtonView; +import com.android.systemui.navigationbar.buttons.ReverseLinearLayout; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.shared.system.QuickStepContract; -import com.android.systemui.statusbar.phone.ReverseLinearLayout.ReverseRelativeLayout; -import com.android.systemui.statusbar.policy.KeyButtonView; +import com.android.systemui.navigationbar.buttons.ReverseLinearLayout.ReverseRelativeLayout; import java.io.PrintWriter; import java.util.Objects; @@ -472,8 +476,7 @@ public class NavigationBarInflaterView extends FrameLayout } public void dump(PrintWriter pw) { - pw.println("NavigationBarInflaterView {"); - pw.println(" mCurrentLayout: " + mCurrentLayout); - pw.println(" }"); + pw.println("NavigationBarInflaterView"); + pw.println(" mCurrentLayout: " + mCurrentLayout); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java index 1f509549efd1..c0535b5fc77b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,27 +14,27 @@ * limitations under the License. */ -package com.android.systemui.statusbar.phone; +package com.android.systemui.navigationbar; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; import static com.android.systemui.util.Utils.isGesturalModeOnDefaultDisplay; -import android.content.Context; import android.graphics.Rect; import android.os.Handler; import android.os.RemoteException; -import android.os.ServiceManager; import android.util.SparseArray; import android.view.Display; import android.view.IWallpaperVisibilityListener; import android.view.IWindowManager; import android.view.View; -import com.android.internal.statusbar.IStatusBarService; import com.android.systemui.Dependency; import com.android.systemui.R; +import com.android.systemui.navigationbar.buttons.ButtonDispatcher; import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.phone.BarTransitions; +import com.android.systemui.statusbar.phone.LightBarTransitionsController; import java.util.ArrayList; import java.util.List; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java index e3cb105ba2f7..a3351838ecf2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.phone; +package com.android.systemui.navigationbar; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; @@ -70,6 +70,15 @@ import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.assist.AssistHandleViewController; import com.android.systemui.model.SysUiState; +import com.android.systemui.navigationbar.buttons.ButtonDispatcher; +import com.android.systemui.navigationbar.buttons.ContextualButton; +import com.android.systemui.navigationbar.buttons.ContextualButtonGroup; +import com.android.systemui.navigationbar.buttons.DeadZone; +import com.android.systemui.navigationbar.buttons.KeyButtonDrawable; +import com.android.systemui.navigationbar.buttons.RotationContextButton; +import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler; +import com.android.systemui.navigationbar.gestural.FloatingRotationButton; +import com.android.systemui.navigationbar.gestural.RegionSamplingHelper; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsOnboarding; @@ -80,9 +89,10 @@ import com.android.systemui.shared.system.SysUiStatsLog; import com.android.systemui.shared.system.WindowManagerWrapper; import com.android.systemui.stackdivider.Divider; import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.NavigationBarController; -import com.android.systemui.statusbar.policy.DeadZone; -import com.android.systemui.statusbar.policy.KeyButtonDrawable; +import com.android.systemui.statusbar.phone.AutoHideController; +import com.android.systemui.statusbar.phone.LightBarTransitionsController; +import com.android.systemui.statusbar.phone.NotificationPanelViewController; +import com.android.systemui.statusbar.phone.StatusBar; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -167,7 +177,7 @@ public class NavigationBarView extends FrameLayout implements * When quickswitching between apps of different orientations, we draw a secondary home handle * in the position of the first app's orientation. This rect represents the region of that * home handle so we can apply the correct light/dark luma on that. - * @see {@link NavigationBarFragment#mOrientationHandle} + * @see {@link NavigationBar#mOrientationHandle} */ @Nullable private Rect mOrientedHandleSamplingRegion; @@ -779,7 +789,7 @@ public class NavigationBarView extends FrameLayout implements } else { return; } - WindowManager wm = (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE); + WindowManager wm = getContext().getSystemService(WindowManager.class); wm.updateViewLayout((View) getParent(), lp); } } @@ -867,7 +877,7 @@ public class NavigationBarView extends FrameLayout implements } else { lp.flags &= ~flags; } - WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); + WindowManager wm = getContext().getSystemService(WindowManager.class); wm.updateViewLayout(navbarView, lp); } @@ -1163,6 +1173,9 @@ public class NavigationBarView extends FrameLayout implements @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); + // This needs to happen first as it can changed the enabled state which can affect whether + // the back button is visible + mEdgeBackGestureHandler.onNavBarAttached(); requestApplyInsets(); reorient(); onNavigationModeChanged(mNavBarMode); @@ -1171,7 +1184,6 @@ public class NavigationBarView extends FrameLayout implements mRotationButtonController.registerListeners(); } - mEdgeBackGestureHandler.onNavBarAttached(); getViewTreeObserver().addOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener); } @@ -1200,12 +1212,12 @@ public class NavigationBarView extends FrameLayout implements } } - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println("NavigationBarView {"); + public void dump(PrintWriter pw) { final Rect r = new Rect(); final Point size = new Point(); getContextDisplay().getRealSize(size); + pw.println("NavigationBarView:"); pw.println(String.format(" this: " + StatusBar.viewInfo(this) + " " + visibilityToString(getVisibility()))); @@ -1228,6 +1240,8 @@ public class NavigationBarView extends FrameLayout implements getLightTransitionsController().getCurrentDarkIntensity())); pw.println(" mOrientedHandleSamplingRegion: " + mOrientedHandleSamplingRegion); + pw.println(" mScreenOn: " + mScreenOn); + dumpButton(pw, "back", getBackButton()); dumpButton(pw, "home", getHomeButton()); @@ -1236,9 +1250,6 @@ public class NavigationBarView extends FrameLayout implements dumpButton(pw, "a11y", getAccessibilityButton()); dumpButton(pw, "ime", getImeSwitchButton()); - pw.println(" }"); - pw.println(" mScreenOn: " + mScreenOn); - if (mNavigationInflaterView != null) { mNavigationInflaterView.dump(pw); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java index c211de08cb8e..6e301c915af7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.phone; +package com.android.systemui.navigationbar; import static android.content.Intent.ACTION_OVERLAY_CHANGED; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButton.java b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButton.java index 74d4eb175ac4..e48785844347 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButton.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButton.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,16 +14,16 @@ * limitations under the License. */ -package com.android.systemui.statusbar.phone; +package com.android.systemui.navigationbar; import android.view.View; -import com.android.systemui.statusbar.policy.KeyButtonDrawable; +import com.android.systemui.navigationbar.buttons.KeyButtonDrawable; import java.util.function.Consumer; /** Interface of a rotation button that interacts {@link RotationButtonController}. */ -interface RotationButton { +public interface RotationButton { void setRotationButtonController(RotationButtonController rotationButtonController); void setVisibilityChangedCallback(Consumer<Boolean> visibilityChangedCallback); View getCurrentView(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java index 2f2e1f9a1f2e..6cbf065ea6a9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.phone; +package com.android.systemui.navigationbar; import static com.android.internal.view.RotationPolicy.NATURAL_ROTATION; @@ -23,7 +23,6 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.annotation.ColorInt; import android.annotation.DrawableRes; -import android.annotation.StyleRes; import android.app.StatusBarManager; import android.content.ContentResolver; import android.content.Context; @@ -32,7 +31,6 @@ import android.os.Looper; import android.os.RemoteException; import android.provider.Settings; import android.util.Log; -import android.view.ContextThemeWrapper; import android.view.IRotationWatcher.Stub; import android.view.MotionEvent; import android.view.Surface; @@ -43,14 +41,13 @@ import android.view.accessibility.AccessibilityManager; import com.android.internal.logging.UiEvent; import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.UiEventLoggerImpl; -import com.android.settingslib.Utils; import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; +import com.android.systemui.navigationbar.buttons.KeyButtonDrawable; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; -import com.android.systemui.statusbar.policy.KeyButtonDrawable; import com.android.systemui.statusbar.policy.RotationLockController; import java.util.Optional; @@ -328,7 +325,7 @@ public class RotationButtonController { } } - Context getContext() { + public Context getContext() { return mContext; } @@ -336,15 +333,15 @@ public class RotationButtonController { return mRotationButton; } - @DrawableRes int getIconResId() { + public @DrawableRes int getIconResId() { return mIconResId; } - @ColorInt int getLightIconColor() { + public @ColorInt int getLightIconColor() { return mLightIconColor; } - @ColorInt int getDarkIconColor() { + public @ColorInt int getDarkIconColor() { return mDarkIconColor; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenPinningNotify.java b/packages/SystemUI/src/com/android/systemui/navigationbar/ScreenPinningNotify.java index 071e00d08d67..ac7baf592599 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenPinningNotify.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/ScreenPinningNotify.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.phone; +package com.android.systemui.navigationbar; import android.content.Context; import android.os.SystemClock; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java index c2731089132c..ade2923acdf6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonDispatcher.java @@ -1,18 +1,20 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2020 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 + * 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. + * 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.statusbar.phone; +package com.android.systemui.navigationbar.buttons; import static com.android.systemui.Interpolators.LINEAR; @@ -24,7 +26,6 @@ import android.view.View.AccessibilityDelegate; import com.android.systemui.Dependency; import com.android.systemui.assist.AssistManager; -import com.android.systemui.statusbar.policy.KeyButtonDrawable; import java.util.ArrayList; @@ -75,11 +76,11 @@ public class ButtonDispatcher { mAssistManager = Dependency.get(AssistManager.class); } - void clear() { + public void clear() { mViews.clear(); } - void addView(View view) { + public void addView(View view) { mViews.add(view); view.setOnClickListener(mClickListener); view.setOnTouchListener(mTouchListener); @@ -337,6 +338,6 @@ public class ButtonDispatcher { /** * Executes when button is detached from window. */ - protected void onDestroy() { + public void onDestroy() { } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonInterface.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonInterface.java index 150a9603a124..8d291ddf5f19 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonInterface.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ButtonInterface.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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. @@ -11,10 +11,10 @@ * 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 + * limitations under the License. */ -package com.android.systemui.statusbar.phone; +package com.android.systemui.navigationbar.buttons; import android.annotation.Nullable; import android.graphics.drawable.Drawable; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ContextualButton.java index eb476457dcec..453e85ae25c7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ContextualButton.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2020 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. @@ -11,10 +11,10 @@ * 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 + * limitations under the License. */ -package com.android.systemui.statusbar.phone; +package com.android.systemui.navigationbar.buttons; import android.annotation.DrawableRes; import android.annotation.IdRes; @@ -22,9 +22,6 @@ import android.annotation.NonNull; import android.content.Context; import android.view.View; -import com.android.systemui.statusbar.policy.KeyButtonDrawable; -import com.android.systemui.statusbar.policy.KeyButtonView; - /** * Simple contextual button that is added to the {@link ContextualButtonGroup}. Extend if need extra * functionality. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButtonGroup.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ContextualButtonGroup.java index c1017f4def0f..50b638bcc903 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButtonGroup.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ContextualButtonGroup.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2020 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. @@ -11,10 +11,10 @@ * 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 + * limitations under the License. */ -package com.android.systemui.statusbar.phone; +package com.android.systemui.navigationbar.buttons; import android.annotation.IdRes; import android.annotation.NonNull; @@ -119,21 +119,20 @@ public class ContextualButtonGroup extends ButtonDispatcher { public void dump(PrintWriter pw) { View view = getCurrentView(); - pw.println("ContextualButtonGroup {"); - pw.println(" getVisibleContextButton(): " + getVisibleContextButton()); - pw.println(" isVisible(): " + isVisible()); - pw.println(" attached(): " + (view != null && view.isAttachedToWindow())); - pw.println(" mButtonData [ "); + pw.println("ContextualButtonGroup"); + pw.println(" getVisibleContextButton(): " + getVisibleContextButton()); + pw.println(" isVisible(): " + isVisible()); + pw.println(" attached(): " + (view != null && view.isAttachedToWindow())); + pw.println(" mButtonData [ "); for (int i = mButtonData.size() - 1; i >= 0; --i) { final ButtonData data = mButtonData.get(i); view = data.button.getCurrentView(); - pw.println(" " + i + ": markedVisible=" + data.markedVisible + pw.println(" " + i + ": markedVisible=" + data.markedVisible + " visible=" + data.button.getVisibility() + " attached=" + (view != null && view.isAttachedToWindow()) + " alpha=" + data.button.getAlpha()); } - pw.println(" ]"); - pw.println(" }"); + pw.println(" ]"); } private int getContextButtonIndex(@IdRes int buttonResId) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/DeadZone.java index 12d0617d90ff..7e5b5548237b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/DeadZone.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.policy; +package com.android.systemui.navigationbar.buttons; import android.animation.ObjectAnimator; import android.content.res.Resources; @@ -26,8 +26,8 @@ import android.view.Surface; import com.android.systemui.Dependency; import com.android.systemui.R; -import com.android.systemui.statusbar.NavigationBarController; -import com.android.systemui.statusbar.phone.NavigationBarView; +import com.android.systemui.navigationbar.NavigationBarController; +import com.android.systemui.navigationbar.NavigationBarView; /** * The "dead zone" consumes unintentional taps along the top edge of the navigation bar. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonDrawable.java index 755938863b5e..fc2016913292 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonDrawable.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 The Android Open Source Project + * Copyright (C) 2020 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. @@ -11,10 +11,10 @@ * 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 + * limitations under the License. */ -package com.android.systemui.statusbar.policy; +package com.android.systemui.navigationbar.buttons; import android.animation.ArgbEvaluator; import android.annotation.ColorInt; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonRipple.java index 2d8784dc41bd..72cd4f1343e6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonRipple.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 The Android Open Source Project + * Copyright (C) 2020 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. @@ -11,10 +11,10 @@ * 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 + * limitations under the License. */ -package com.android.systemui.statusbar.policy; +package com.android.systemui.navigationbar.buttons; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java index 8d7ecd09e760..d6b831640326 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.policy; +package com.android.systemui.navigationbar.buttons; import static android.view.Display.INVALID_DISPLAY; import static android.view.KeyEvent.KEYCODE_UNKNOWN; @@ -61,7 +61,6 @@ import com.android.systemui.R; import com.android.systemui.bubbles.BubbleController; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.shared.system.QuickStepContract; -import com.android.systemui.statusbar.phone.ButtonInterface; public class KeyButtonView extends ImageView implements ButtonInterface { private static final String TAG = KeyButtonView.class.getSimpleName(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NearestTouchFrame.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/NearestTouchFrame.java index d02280836fb5..88c8fea085fb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NearestTouchFrame.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/NearestTouchFrame.java @@ -1,18 +1,20 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2020 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 + * 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. + * 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.statusbar.phone; +package com.android.systemui.navigationbar.buttons; import android.content.Context; import android.content.res.Configuration; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ReverseLinearLayout.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ReverseLinearLayout.java index d3ec187ef20f..f1e1366404a2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ReverseLinearLayout.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ReverseLinearLayout.java @@ -12,7 +12,7 @@ * permissions and limitations under the License. */ -package com.android.systemui.statusbar.phone; +package com.android.systemui.navigationbar.buttons; import android.annotation.Nullable; import android.content.Context; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/RotationContextButton.java index d63d445d8ba3..6a97a3379939 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/RotationContextButton.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2020 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. @@ -11,17 +11,20 @@ * 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 + * limitations under the License. */ -package com.android.systemui.statusbar.phone; +package com.android.systemui.navigationbar.buttons; import android.annotation.DrawableRes; import android.annotation.IdRes; import android.content.Context; import android.view.View; -import com.android.systemui.statusbar.policy.KeyButtonDrawable; +import com.android.systemui.navigationbar.RotationButton; +import com.android.systemui.navigationbar.RotationButtonController; +import com.android.systemui.navigationbar.buttons.ContextualButton; +import com.android.systemui.navigationbar.buttons.KeyButtonDrawable; import java.util.function.Consumer; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java index 9606318e1992..a1b55c428029 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java @@ -1,5 +1,5 @@ -/** - * Copyright (C) 2019 The Android Open Source Project +/* + * Copyright (C) 2020 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.systemui.statusbar.phone; +package com.android.systemui.navigationbar.gestural; import static android.view.Display.INVALID_DISPLAY; @@ -59,6 +59,8 @@ import com.android.systemui.R; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.bubbles.BubbleController; import com.android.systemui.model.SysUiState; +import com.android.systemui.navigationbar.NavigationBarView; +import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.plugins.NavigationEdgeBackPlugin; import com.android.systemui.plugins.PluginListener; import com.android.systemui.recents.OverviewProxyService; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButton.java index 8a85f7d6a2c5..61118c5d26ac 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/FloatingRotationButton.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.phone; +package com.android.systemui.navigationbar.gestural; import android.content.Context; import android.content.res.Resources; @@ -27,8 +27,10 @@ import android.view.View; import android.view.WindowManager; import com.android.systemui.R; -import com.android.systemui.statusbar.policy.KeyButtonDrawable; -import com.android.systemui.statusbar.policy.KeyButtonView; +import com.android.systemui.navigationbar.RotationButton; +import com.android.systemui.navigationbar.RotationButtonController; +import com.android.systemui.navigationbar.buttons.KeyButtonDrawable; +import com.android.systemui.navigationbar.buttons.KeyButtonView; import java.util.function.Consumer; @@ -49,7 +51,7 @@ public class FloatingRotationButton implements RotationButton { private RotationButtonController mRotationButtonController; private Consumer<Boolean> mVisibilityChangedCallback; - FloatingRotationButton(Context context) { + public FloatingRotationButton(Context context) { mContext = context; mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); mKeyButtonView = (KeyButtonView) LayoutInflater.from(mContext).inflate( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java index 23573095e037..284f41a416d6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.phone; +package com.android.systemui.navigationbar.gestural; import android.animation.ValueAnimator; import android.content.Context; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationHandle.java index b87479505d00..33e6aa46724b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationHandle.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.phone; +package com.android.systemui.navigationbar.gestural; import android.animation.ArgbEvaluator; import android.annotation.ColorInt; @@ -29,6 +29,7 @@ import android.view.View; import com.android.settingslib.Utils; import com.android.systemui.R; +import com.android.systemui.navigationbar.buttons.ButtonInterface; public class NavigationHandle extends View implements ButtonInterface { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickswitchOrientedNavHandle.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/QuickswitchOrientedNavHandle.java index fe74677a8d51..71c8a2c1e6ca 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickswitchOrientedNavHandle.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/QuickswitchOrientedNavHandle.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.phone; +package com.android.systemui.navigationbar.gestural; import android.content.Context; import android.graphics.Canvas; @@ -34,7 +34,7 @@ public class QuickswitchOrientedNavHandle extends NavigationHandle { mWidth = context.getResources().getDimensionPixelSize(R.dimen.navigation_home_handle_width); } - void setDeltaRotation(@Surface.Rotation int rotation) { + public void setDeltaRotation(@Surface.Rotation int rotation) { mDeltaRotation = rotation; } @@ -43,7 +43,7 @@ public class QuickswitchOrientedNavHandle extends NavigationHandle { canvas.drawRoundRect(computeHomeHandleBounds(), mRadius, mRadius, mPaint); } - RectF computeHomeHandleBounds() { + public RectF computeHomeHandleBounds() { int left; int top; int bottom; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RegionSamplingHelper.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/RegionSamplingHelper.java index 3c8aa86dd209..70117eb6d2f0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RegionSamplingHelper.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/RegionSamplingHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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. @@ -11,10 +11,10 @@ * 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 + * limitations under the License. */ -package com.android.systemui.statusbar.phone; +package com.android.systemui.navigationbar.gestural; import static android.view.Display.DEFAULT_DISPLAY; @@ -108,7 +108,7 @@ public class RegionSamplingHelper implements View.OnAttachStateChangeListener, } } - void start(Rect initialSamplingBounds) { + public void start(Rect initialSamplingBounds) { if (!mCallback.isSamplingEnabled()) { return; } @@ -122,12 +122,12 @@ public class RegionSamplingHelper implements View.OnAttachStateChangeListener, updateSamplingListener(); } - void stop() { + public void stop() { mSamplingEnabled = false; updateSamplingListener(); } - void stopAndDestroy() { + public void stopAndDestroy() { stop(); mSamplingListener.destroy(); mIsDestroyed = true; @@ -220,12 +220,12 @@ public class RegionSamplingHelper implements View.OnAttachStateChangeListener, } } - void setWindowVisible(boolean visible) { + public void setWindowVisible(boolean visible) { mWindowVisible = visible; updateSamplingListener(); } - void dump(PrintWriter pw) { + public void dump(PrintWriter pw) { pw.println("RegionSamplingHelper:"); pw.println(" sampleView isAttached: " + mSampledView.isAttachedToWindow()); pw.println(" sampleView isScValid: " + (mSampledView.isAttachedToWindow() diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java index 8550959aa2c4..2e91697de849 100644 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java @@ -26,6 +26,7 @@ import android.graphics.Point; import android.graphics.Rect; import android.os.Handler; import android.os.Looper; +import android.os.SystemProperties; import android.util.Log; import android.view.SurfaceControl; import android.window.DisplayAreaInfo; @@ -61,6 +62,8 @@ import javax.inject.Inject; */ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer implements Dumpable { private static final String TAG = "OneHandedDisplayAreaOrganizer"; + private static final String ONE_HANDED_MODE_TRANSLATE_ANIMATION_DURATION = + "persist.debug.one_handed_translate_animation_duration"; @VisibleForTesting static final int MSG_RESET_IMMEDIATE = 1; @@ -156,8 +159,8 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer implemen mDisplayController = displayController; mDefaultDisplayBounds.set(getDisplayBounds()); mLastVisualDisplayBounds.set(getDisplayBounds()); - mEnterExitAnimationDurationMs = context.getResources().getInteger( - com.android.systemui.R.integer.config_one_handed_translate_animation_duration); + mEnterExitAnimationDurationMs = + SystemProperties.getInt(ONE_HANDED_MODE_TRANSLATE_ANIMATION_DURATION, 300); mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new; mTutorialHandler = tutorialHandler; } diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java index 563684ad65c1..ba50db1c9f72 100644 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java @@ -40,7 +40,7 @@ import android.window.WindowContainerTransaction; import androidx.annotation.VisibleForTesting; import com.android.systemui.R; -import com.android.systemui.statusbar.phone.NavigationModeController; +import com.android.systemui.navigationbar.NavigationModeController; import com.android.wm.shell.common.DisplayChangeController; import com.android.wm.shell.common.DisplayController; diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java index a3921ee54fec..42524bb33818 100644 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java @@ -24,13 +24,13 @@ import android.content.ComponentName; import android.content.Context; import android.graphics.Point; import android.graphics.Rect; +import android.os.SystemProperties; import android.view.KeyEvent; import androidx.annotation.NonNull; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.Dumpable; -import com.android.systemui.R; import com.android.systemui.model.SysUiState; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.TaskStackChangeListener; @@ -50,6 +50,8 @@ import javax.inject.Singleton; @Singleton public class OneHandedManagerImpl implements OneHandedManager, Dumpable { private static final String TAG = "OneHandedManager"; + private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE = + "persist.debug.one_handed_offset_percentage"; private boolean mIsOneHandedEnabled; private boolean mIsSwipeToNotificationEnabled; @@ -117,8 +119,8 @@ public class OneHandedManagerImpl implements OneHandedManager, Dumpable { mDisplayController = displayController; mDisplayController.addDisplayChangingController(mRotationController); mSysUiFlagContainer = sysUiState; - mOffSetFraction = - context.getResources().getFraction(R.fraction.config_one_handed_offset, 1, 1); + mOffSetFraction = SystemProperties.getInt(ONE_HANDED_MODE_OFFSET_PERCENTAGE, 50) / 100.0f; + mIsOneHandedEnabled = OneHandedSettingsUtil.getSettingsOneHandedModeEnabled( context.getContentResolver()); mIsSwipeToNotificationEnabled = OneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled( diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedSettingsUtil.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedSettingsUtil.java index 1b6ec04193f0..279bbc862ff0 100644 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedSettingsUtil.java +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedSettingsUtil.java @@ -22,19 +22,13 @@ import android.database.ContentObserver; import android.net.Uri; import android.provider.Settings; -import com.android.internal.annotations.VisibleForTesting; - import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import javax.inject.Inject; -import javax.inject.Singleton; - /** * APIs for querying or updating one handed settings . */ -@Singleton public final class OneHandedSettingsUtil { private static final String TAG = "OneHandedSettingsUtil"; @@ -65,11 +59,6 @@ public final class OneHandedSettingsUtil { */ public static final int ONE_HANDED_TIMEOUT_LONG_IN_SECONDS = 12; - @VisibleForTesting - @Inject - OneHandedSettingsUtil() { - } - /** * Register one handed preference settings observer * @@ -150,4 +139,6 @@ public final class OneHandedSettingsUtil { pw.print(innerPrefix + "tapsAppToExit="); pw.println(getSettingsTapsAppToExit(resolver)); } + + private OneHandedSettingsUtil() {} } diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java index b28730d004f6..de34b2ec831d 100644 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java @@ -22,6 +22,7 @@ import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; import android.os.Handler; +import android.os.SystemProperties; import android.provider.Settings; import android.view.Gravity; import android.view.LayoutInflater; @@ -50,6 +51,8 @@ import javax.inject.Singleton; @Singleton public class OneHandedTutorialHandler implements OneHandedTransitionCallback, Dumpable { private static final String TAG = "OneHandedTutorialHandler"; + private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE = + "persist.debug.one_handed_offset_percentage"; private static final int MAX_TUTORIAL_SHOW_COUNT = 2; private final Rect mLastUpdatedBounds = new Rect(); private final WindowManager mWindowManager; @@ -81,8 +84,8 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, Du mWindowManager = context.getSystemService(WindowManager.class); mTargetViewContainer = new FrameLayout(context); mTargetViewContainer.setClipChildren(false); - mTutorialAreaHeight = Math.round(mDisplaySize.y * context.getResources().getFraction( - R.fraction.config_one_handed_offset, 1, 1)); + mTutorialAreaHeight = Math.round(mDisplaySize.y + * (SystemProperties.getInt(ONE_HANDED_MODE_OFFSET_PERCENTAGE, 50) / 100.0f)); mTutorialView = LayoutInflater.from(context).inflate(R.xml.one_handed_tutorial, null); mTargetViewContainer.addView(mTutorialView); mCanShowTutorial = (Settings.Secure.getInt(mContentResolver, diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java index 0903c0e5c512..2767a8d18db4 100644 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java @@ -63,7 +63,6 @@ public class OneHandedUI extends SystemUI implements CommandQueue.Callbacks, Dum private final CommandQueue mCommandQueue; private final Handler mMainHandler = new Handler(Looper.getMainLooper()); private final IOverlayManager mOverlayManager; - private final OneHandedSettingsUtil mSettingUtil; private final OneHandedTimeoutHandler mTimeoutHandler; private final ScreenLifecycle mScreenLifecycle; @@ -154,7 +153,6 @@ public class OneHandedUI extends SystemUI implements CommandQueue.Callbacks, Dum public OneHandedUI(Context context, CommandQueue commandQueue, OneHandedManagerImpl oneHandedManager, - OneHandedSettingsUtil settingsUtil, ScreenLifecycle screenLifecycle) { super(context); @@ -163,7 +161,6 @@ public class OneHandedUI extends SystemUI implements CommandQueue.Callbacks, Dum mCommandQueue = null; mOneHandedManager = null; mOverlayManager = null; - mSettingUtil = null; mTimeoutHandler = null; mScreenLifecycle = null; return; @@ -171,7 +168,6 @@ public class OneHandedUI extends SystemUI implements CommandQueue.Callbacks, Dum mCommandQueue = commandQueue; mOneHandedManager = oneHandedManager; - mSettingUtil = settingsUtil; mTimeoutHandler = OneHandedTimeoutHandler.get(); mScreenLifecycle = screenLifecycle; mOverlayManager = IOverlayManager.Stub.asInterface( @@ -252,26 +248,26 @@ public class OneHandedUI extends SystemUI implements CommandQueue.Callbacks, Dum } private void setupSettingObservers() { - mSettingUtil.registerSettingsKeyObserver(Settings.Secure.ONE_HANDED_MODE_ENABLED, + OneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.ONE_HANDED_MODE_ENABLED, mContext.getContentResolver(), mEnabledObserver); - mSettingUtil.registerSettingsKeyObserver(Settings.Secure.ONE_HANDED_MODE_TIMEOUT, + OneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.ONE_HANDED_MODE_TIMEOUT, mContext.getContentResolver(), mTimeoutObserver); - mSettingUtil.registerSettingsKeyObserver(Settings.Secure.TAPS_APP_TO_EXIT, + OneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.TAPS_APP_TO_EXIT, mContext.getContentResolver(), mTaskChangeExitObserver); - mSettingUtil.registerSettingsKeyObserver( + OneHandedSettingsUtil.registerSettingsKeyObserver( Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, mContext.getContentResolver(), mSwipeToNotificationEnabledObserver); } private void updateSettings() { - mOneHandedManager.setOneHandedEnabled( - mSettingUtil.getSettingsOneHandedModeEnabled(mContext.getContentResolver())); - mTimeoutHandler.setTimeout( - mSettingUtil.getSettingsOneHandedModeTimeout(mContext.getContentResolver())); - mOneHandedManager.setTaskChangeToExit( - mSettingUtil.getSettingsTapsAppToExit(mContext.getContentResolver())); - mOneHandedManager.setSwipeToNotificationEnabled( - mSettingUtil.getSettingsSwipeToNotificationEnabled(mContext.getContentResolver())); + mOneHandedManager.setOneHandedEnabled(OneHandedSettingsUtil + .getSettingsOneHandedModeEnabled(mContext.getContentResolver())); + mTimeoutHandler.setTimeout(OneHandedSettingsUtil + .getSettingsOneHandedModeTimeout(mContext.getContentResolver())); + mOneHandedManager.setTaskChangeToExit(OneHandedSettingsUtil + .getSettingsTapsAppToExit(mContext.getContentResolver())); + mOneHandedManager.setSwipeToNotificationEnabled(OneHandedSettingsUtil + .getSettingsSwipeToNotificationEnabled(mContext.getContentResolver())); } @Override @@ -326,9 +322,7 @@ public class OneHandedUI extends SystemUI implements CommandQueue.Callbacks, Dum mTimeoutHandler.dump(fd, pw, args); } - if (mSettingUtil != null) { - mSettingUtil.dump(pw, innerPrefix, mContext.getContentResolver()); - } + OneHandedSettingsUtil.dump(pw, innerPrefix, mContext.getContentResolver()); if (mOverlayManager != null) { OverlayInfo info = null; diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index d03082e6b442..ecdd7780a3f4 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -61,12 +61,18 @@ import android.view.MotionEvent; import android.view.Surface; import android.view.accessibility.AccessibilityManager; +import androidx.annotation.NonNull; + import com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity; import com.android.internal.policy.ScreenDecorationsUtils; import com.android.internal.util.ScreenshotHelper; import com.android.systemui.Dumpable; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.model.SysUiState; +import com.android.systemui.navigationbar.NavigationBar; +import com.android.systemui.navigationbar.NavigationBarController; +import com.android.systemui.navigationbar.NavigationBarView; +import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.onehanded.OneHandedUI; import com.android.systemui.pip.PipAnimationController; import com.android.systemui.pip.PipUI; @@ -81,10 +87,6 @@ import com.android.systemui.shared.system.InputMonitorCompat; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.stackdivider.Divider; import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.NavigationBarController; -import com.android.systemui.statusbar.phone.NavigationBarFragment; -import com.android.systemui.statusbar.phone.NavigationBarView; -import com.android.systemui.statusbar.phone.NavigationModeController; import com.android.systemui.statusbar.phone.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarWindowCallback; @@ -124,7 +126,7 @@ public class OverviewProxyService extends CurrentUserTracker implements private final Optional<Divider> mDividerOptional; private SysUiState mSysUiState; private final Handler mHandler; - private final NavigationBarController mNavBarController; + private final Lazy<NavigationBarController> mNavBarControllerLazy; private final NotificationShadeWindowController mStatusBarWinController; private final Runnable mConnectionRunnable = this::internalConnectToCurrentUser; private final ComponentName mRecentsComponentName; @@ -598,7 +600,7 @@ public class OverviewProxyService extends CurrentUserTracker implements @SuppressWarnings("OptionalUsedAsFieldOrParameterType") @Inject public OverviewProxyService(Context context, CommandQueue commandQueue, - NavigationBarController navBarController, NavigationModeController navModeController, + Lazy<NavigationBarController> navBarControllerLazy, NavigationModeController navModeController, NotificationShadeWindowController statusBarWinController, SysUiState sysUiState, PipUI pipUI, Optional<Divider> dividerOptional, Optional<Lazy<StatusBar>> statusBarOptionalLazy, OneHandedUI oneHandedUI, @@ -608,7 +610,7 @@ public class OverviewProxyService extends CurrentUserTracker implements mPipUI = pipUI; mStatusBarOptionalLazy = statusBarOptionalLazy; mHandler = new Handler(); - mNavBarController = navBarController; + mNavBarControllerLazy = navBarControllerLazy; mStatusBarWinController = statusBarWinController; mConnectionBackoffAttempts = 0; mDividerOptional = dividerOptional; @@ -677,10 +679,10 @@ public class OverviewProxyService extends CurrentUserTracker implements } private void updateSystemUiStateFlags() { - final NavigationBarFragment navBarFragment = - mNavBarController.getDefaultNavigationBarFragment(); + final NavigationBar navBarFragment = + mNavBarControllerLazy.get().getDefaultNavigationBar(); final NavigationBarView navBarView = - mNavBarController.getNavigationBarView(mContext.getDisplayId()); + mNavBarControllerLazy.get().getNavigationBarView(mContext.getDisplayId()); if (SysUiState.DEBUG) { Log.d(TAG_OPS, "Updating sysui state flags: navBarFragment=" + navBarFragment + " navBarView=" + navBarView); @@ -808,7 +810,7 @@ public class OverviewProxyService extends CurrentUserTracker implements } @Override - public void addCallback(OverviewProxyListener listener) { + public void addCallback(@NonNull OverviewProxyListener listener) { if (!mConnectionCallbacks.contains(listener)) { mConnectionCallbacks.add(listener); } @@ -817,7 +819,7 @@ public class OverviewProxyService extends CurrentUserTracker implements } @Override - public void removeCallback(OverviewProxyListener listener) { + public void removeCallback(@NonNull OverviewProxyListener listener) { mConnectionCallbacks.remove(listener); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java index 3b3d9dde3b7e..9c5a3de4523a 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java @@ -466,23 +466,22 @@ public class RecentsOnboarding { } public void dump(PrintWriter pw) { - pw.println("RecentsOnboarding {"); - pw.println(" mTaskListenerRegistered: " + mTaskListenerRegistered); - pw.println(" mOverviewProxyListenerRegistered: " + mOverviewProxyListenerRegistered); - pw.println(" mLayoutAttachedToWindow: " + mLayoutAttachedToWindow); - pw.println(" mHasDismissedSwipeUpTip: " + mHasDismissedSwipeUpTip); - pw.println(" mHasDismissedQuickScrubTip: " + mHasDismissedQuickScrubTip); - pw.println(" mNumAppsLaunchedSinceSwipeUpTipDismiss: " + pw.println("RecentsOnboarding"); + pw.println(" mTaskListenerRegistered: " + mTaskListenerRegistered); + pw.println(" mOverviewProxyListenerRegistered: " + mOverviewProxyListenerRegistered); + pw.println(" mLayoutAttachedToWindow: " + mLayoutAttachedToWindow); + pw.println(" mHasDismissedSwipeUpTip: " + mHasDismissedSwipeUpTip); + pw.println(" mHasDismissedQuickScrubTip: " + mHasDismissedQuickScrubTip); + pw.println(" mNumAppsLaunchedSinceSwipeUpTipDismiss: " + mNumAppsLaunchedSinceSwipeUpTipDismiss); - pw.println(" hasSeenSwipeUpOnboarding: " + hasSeenSwipeUpOnboarding()); - pw.println(" hasSeenQuickScrubOnboarding: " + hasSeenQuickScrubOnboarding()); - pw.println(" getDismissedSwipeUpOnboardingCount: " + pw.println(" hasSeenSwipeUpOnboarding: " + hasSeenSwipeUpOnboarding()); + pw.println(" hasSeenQuickScrubOnboarding: " + hasSeenQuickScrubOnboarding()); + pw.println(" getDismissedSwipeUpOnboardingCount: " + getDismissedSwipeUpOnboardingCount()); - pw.println(" hasDismissedQuickScrubOnboardingOnce: " + pw.println(" hasDismissedQuickScrubOnboardingOnce: " + hasDismissedQuickScrubOnboardingOnce()); - pw.println(" getOpenedOverviewCount: " + getOpenedOverviewCount()); - pw.println(" getOpenedOverviewFromHomeCount: " + getOpenedOverviewFromHomeCount()); - pw.println(" }"); + pw.println(" getOpenedOverviewCount: " + getOpenedOverviewCount()); + pw.println(" getOpenedOverviewFromHomeCount: " + getOpenedOverviewFromHomeCount()); } private WindowManager.LayoutParams getWindowLayoutParams(int gravity, int x) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java index 387490311644..6afc75624a9f 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java +++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java @@ -51,8 +51,8 @@ import com.android.systemui.R; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.shared.system.WindowManagerWrapper; -import com.android.systemui.statusbar.phone.NavigationBarView; -import com.android.systemui.statusbar.phone.NavigationModeController; +import com.android.systemui.navigationbar.NavigationBarView; +import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.util.leak.RotationUtils; diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java index 82ac1f6f6a33..4da2bb66d41b 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java @@ -26,6 +26,8 @@ import android.os.CountDownTimer; import android.os.UserHandle; import android.util.Log; +import androidx.annotation.NonNull; + import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.statusbar.policy.CallbackController; @@ -191,12 +193,12 @@ public class RecordingController } @Override - public void addCallback(RecordingStateChangeCallback listener) { + public void addCallback(@NonNull RecordingStateChangeCallback listener) { mListeners.add(listener); } @Override - public void removeCallback(RecordingStateChangeCallback listener) { + public void removeCallback(@NonNull RecordingStateChangeCallback listener) { mListeners.remove(listener); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index 1638dd9664a4..4673ec73c25a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -49,6 +49,8 @@ import android.util.SparseArray; import android.view.InsetsState.InternalInsetsType; import android.view.WindowInsetsController.Appearance; +import androidx.annotation.NonNull; + import com.android.internal.os.SomeArgs; import com.android.internal.statusbar.IStatusBar; import com.android.internal.statusbar.StatusBarIcon; @@ -391,7 +393,8 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< && !ONLY_CORE_APPS; } - public void addCallback(Callbacks callbacks) { + @Override + public void addCallback(@NonNull Callbacks callbacks) { mCallbacks.add(callbacks); // TODO(b/117478341): find a better way to pass disable flags by display. for (int i = 0; i < mDisplayDisabled.size(); i++) { @@ -402,7 +405,8 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< } } - public void removeCallback(Callbacks callbacks) { + @Override + public void removeCallback(@NonNull Callbacks callbacks) { mCallbacks.remove(callbacks); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java deleted file mode 100644 index 2638d28733e8..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright (C) 2018 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.statusbar; - -import static android.view.Display.DEFAULT_DISPLAY; - -import android.content.Context; -import android.hardware.display.DisplayManager; -import android.os.Handler; -import android.os.RemoteException; -import android.util.Log; -import android.util.SparseArray; -import android.view.Display; -import android.view.IWindowManager; -import android.view.View; -import android.view.WindowManagerGlobal; - -import androidx.annotation.Nullable; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.statusbar.RegisterStatusBarResult; -import com.android.systemui.Dependency; -import com.android.systemui.assist.AssistHandleViewController; -import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.fragments.FragmentHostManager; -import com.android.systemui.plugins.DarkIconDispatcher; -import com.android.systemui.statusbar.CommandQueue.Callbacks; -import com.android.systemui.statusbar.phone.AutoHideController; -import com.android.systemui.statusbar.phone.BarTransitions.TransitionMode; -import com.android.systemui.statusbar.phone.LightBarController; -import com.android.systemui.statusbar.phone.NavigationBarFragment; -import com.android.systemui.statusbar.phone.NavigationBarView; -import com.android.systemui.statusbar.phone.NavigationModeController; -import com.android.systemui.statusbar.policy.BatteryController; - -import javax.inject.Inject; -import javax.inject.Singleton; - - -/** A controller to handle navigation bars. */ -@Singleton -public class NavigationBarController implements Callbacks { - - private static final String TAG = NavigationBarController.class.getSimpleName(); - - private final Context mContext; - private final Handler mHandler; - private final DisplayManager mDisplayManager; - - /** A displayId - nav bar maps. */ - @VisibleForTesting - SparseArray<NavigationBarFragment> mNavigationBars = new SparseArray<>(); - - @Inject - public NavigationBarController(Context context, @Main Handler handler, - CommandQueue commandQueue) { - mContext = context; - mHandler = handler; - mDisplayManager = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE); - commandQueue.addCallback(this); - } - - @Override - public void onDisplayRemoved(int displayId) { - removeNavigationBar(displayId); - } - - @Override - public void onDisplayReady(int displayId) { - Display display = mDisplayManager.getDisplay(displayId); - createNavigationBar(display, null); - } - - // TODO(b/117478341): I use {@code includeDefaultDisplay} to make this method compatible to - // CarStatusBar because they have their own nav bar. Think about a better way for it. - /** - * Creates navigation bars when car/status bar initializes. - * - * @param includeDefaultDisplay {@code true} to create navigation bar on default display. - */ - public void createNavigationBars(final boolean includeDefaultDisplay, - RegisterStatusBarResult result) { - Display[] displays = mDisplayManager.getDisplays(); - for (Display display : displays) { - if (includeDefaultDisplay || display.getDisplayId() != DEFAULT_DISPLAY) { - createNavigationBar(display, result); - } - } - } - - /** - * Adds a navigation bar on default display or an external display if the display supports - * system decorations. - * - * @param display the display to add navigation bar on. - */ - @VisibleForTesting - void createNavigationBar(Display display, RegisterStatusBarResult result) { - if (display == null) { - return; - } - - final int displayId = display.getDisplayId(); - final boolean isOnDefaultDisplay = displayId == DEFAULT_DISPLAY; - final IWindowManager wms = WindowManagerGlobal.getWindowManagerService(); - - try { - if (!wms.hasNavigationBar(displayId)) { - return; - } - } catch (RemoteException e) { - // Cannot get wms, just return with warning message. - Log.w(TAG, "Cannot get WindowManager."); - return; - } - final Context context = isOnDefaultDisplay - ? mContext - : mContext.createDisplayContext(display); - NavigationBarFragment.create(context, (tag, fragment) -> { - NavigationBarFragment navBar = (NavigationBarFragment) fragment; - - // Unfortunately, we still need it because status bar needs LightBarController - // before notifications creation. We cannot directly use getLightBarController() - // from NavigationBarFragment directly. - LightBarController lightBarController = isOnDefaultDisplay - ? Dependency.get(LightBarController.class) - : new LightBarController(context, - Dependency.get(DarkIconDispatcher.class), - Dependency.get(BatteryController.class), - Dependency.get(NavigationModeController.class)); - navBar.setLightBarController(lightBarController); - - // TODO(b/118592525): to support multi-display, we start to add something which is - // per-display, while others may be global. I think it's time to add - // a new class maybe named DisplayDependency to solve per-display - // Dependency problem. - AutoHideController autoHideController = isOnDefaultDisplay - ? Dependency.get(AutoHideController.class) - : new AutoHideController(context, mHandler, - Dependency.get(IWindowManager.class)); - navBar.setAutoHideController(autoHideController); - navBar.restoreAppearanceAndTransientState(); - mNavigationBars.put(displayId, navBar); - - if (result != null) { - navBar.setImeWindowStatus(display.getDisplayId(), result.mImeToken, - result.mImeWindowVis, result.mImeBackDisposition, - result.mShowImeSwitcher); - } - }); - } - - private void removeNavigationBar(int displayId) { - NavigationBarFragment navBar = mNavigationBars.get(displayId); - if (navBar != null) { - navBar.setAutoHideController(/* autoHideController */ null); - View navigationWindow = navBar.getView().getRootView(); - WindowManagerGlobal.getInstance() - .removeView(navigationWindow, true /* immediate */); - // Also remove FragmentHostState here in case that onViewDetachedFromWindow has not yet - // invoked after display removal. - FragmentHostManager.removeAndDestroy(navigationWindow); - mNavigationBars.remove(displayId); - } - } - - /** @see NavigationBarFragment#checkNavBarModes() */ - public void checkNavBarModes(int displayId) { - NavigationBarFragment navBar = mNavigationBars.get(displayId); - if (navBar != null) { - navBar.checkNavBarModes(); - } - } - - /** @see NavigationBarFragment#finishBarAnimations() */ - public void finishBarAnimations(int displayId) { - NavigationBarFragment navBar = mNavigationBars.get(displayId); - if (navBar != null) { - navBar.finishBarAnimations(); - } - } - - /** @see NavigationBarFragment#touchAutoDim() */ - public void touchAutoDim(int displayId) { - NavigationBarFragment navBar = mNavigationBars.get(displayId); - if (navBar != null) { - navBar.touchAutoDim(); - } - } - - /** @see NavigationBarFragment#transitionTo(int, boolean) */ - public void transitionTo(int displayId, @TransitionMode int barMode, boolean animate) { - NavigationBarFragment navBar = mNavigationBars.get(displayId); - if (navBar != null) { - navBar.transitionTo(barMode, animate); - } - } - - /** @see NavigationBarFragment#disableAnimationsDuringHide(long) */ - public void disableAnimationsDuringHide(int displayId, long delay) { - NavigationBarFragment navBar = mNavigationBars.get(displayId); - if (navBar != null) { - navBar.disableAnimationsDuringHide(delay); - } - } - - /** @return {@link NavigationBarView} on the default display. */ - public @Nullable NavigationBarView getDefaultNavigationBarView() { - return getNavigationBarView(DEFAULT_DISPLAY); - } - - /** - * @param displayId the ID of display which Navigation bar is on - * @return {@link NavigationBarView} on the display with {@code displayId}. - * {@code null} if no navigation bar on that display. - */ - public @Nullable NavigationBarView getNavigationBarView(int displayId) { - NavigationBarFragment navBar = mNavigationBars.get(displayId); - return (navBar == null) ? null : (NavigationBarView) navBar.getView(); - } - - /** @return {@link NavigationBarFragment} on the default display. */ - @Nullable - public NavigationBarFragment getDefaultNavigationBarFragment() { - return mNavigationBars.get(DEFAULT_DISPLAY); - } - - /** @return {@link AssistHandleViewController} (only on the default display). */ - @Nullable - public AssistHandleViewController getAssistHandlerViewController() { - NavigationBarFragment navBar = getDefaultNavigationBarFragment(); - return navBar == null ? null : navBar.getAssistHandlerViewController(); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java index 02a8feec3fa9..f272be477f51 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java @@ -491,7 +491,6 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle } } - row.showAppOpsIcons(entry.mActiveAppOps); row.showFeedbackIcon(mAssistantFeedbackController.showFeedbackIndicator(entry)); row.setLastAudiblyAlertedMs(entry.getLastAudiblyAlertedMs()); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java index 0a7ee3b0ebf0..2aba1038a97d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java @@ -28,8 +28,8 @@ import android.widget.TextView; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.settingslib.WirelessUtils; -import com.android.systemui.DemoMode; import com.android.systemui.Dependency; +import com.android.systemui.demomode.DemoModeCommandReceiver; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver; import com.android.systemui.statusbar.policy.NetworkController; @@ -40,7 +40,8 @@ import com.android.systemui.tuner.TunerService.Tunable; import java.util.List; -public class OperatorNameView extends TextView implements DemoMode, DarkReceiver, +/** Shows the operator name */ +public class OperatorNameView extends TextView implements DemoModeCommandReceiver, DarkReceiver, SignalCallback, Tunable { private static final String KEY_SHOW_OPERATOR_NAME = "show_operator_name"; @@ -103,14 +104,18 @@ public class OperatorNameView extends TextView implements DemoMode, DarkReceiver @Override public void dispatchDemoCommand(String command, Bundle args) { - if (!mDemoMode && command.equals(COMMAND_ENTER)) { - mDemoMode = true; - } else if (mDemoMode && command.equals(COMMAND_EXIT)) { - mDemoMode = false; - update(); - } else if (mDemoMode && command.equals(COMMAND_OPERATOR)) { - setText(args.getString("name")); - } + setText(args.getString("name")); + } + + @Override + public void onDemoModeStarted() { + mDemoMode = true; + } + + @Override + public void onDemoModeFinished() { + mDemoMode = false; + update(); } private void update() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java index 2bef355d59f3..f93078f8b586 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java @@ -23,6 +23,8 @@ import android.util.FloatProperty; import android.util.Log; import android.view.animation.Interpolator; +import androidx.annotation.NonNull; + import com.android.internal.annotations.GuardedBy; import com.android.internal.logging.UiEventLogger; import com.android.systemui.DejankUtils; @@ -276,7 +278,7 @@ public class StatusBarStateControllerImpl implements SysuiStatusBarStateControll } @Override - public void addCallback(StateListener listener) { + public void addCallback(@NonNull StateListener listener) { synchronized (mListeners) { addListenerInternalLocked(listener, Integer.MAX_VALUE); } @@ -316,7 +318,7 @@ public class StatusBarStateControllerImpl implements SysuiStatusBarStateControll @Override - public void removeCallback(StateListener listener) { + public void removeCallback(@NonNull StateListener listener) { synchronized (mListeners) { mListeners.removeIf((it) -> it.mListener.equals(listener)); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java index 68ec6b620a53..2f1208879ebc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinator.java @@ -82,14 +82,9 @@ public class AppOpsCoordinator implements Coordinator { // extend the lifetime of foreground notification services to show for at least 5 seconds mNotifPipeline.addNotificationLifetimeExtender(mForegroundLifetimeExtender); - // listen for new notifications to add appOps - mNotifPipeline.addCollectionListener(mNotifCollectionListener); - // filter out foreground service notifications that aren't necessary anymore mNotifPipeline.addPreGroupFilter(mNotifFilter); - // when appOps change, update any relevant notifications to update appOps for - mAppOpsController.addCallback(ForegroundServiceController.APP_OPS, this::onAppOpsChanged); } public NotifSection getSection() { @@ -186,35 +181,6 @@ public class AppOpsCoordinator implements Coordinator { }; /** - * Adds appOps to incoming and updating notifications - */ - private NotifCollectionListener mNotifCollectionListener = new NotifCollectionListener() { - @Override - public void onEntryAdded(NotificationEntry entry) { - tagAppOps(entry); - } - - @Override - public void onEntryUpdated(NotificationEntry entry) { - tagAppOps(entry); - } - - private void tagAppOps(NotificationEntry entry) { - final StatusBarNotification sbn = entry.getSbn(); - // note: requires that the ForegroundServiceController is updating their appOps first - ArraySet<Integer> activeOps = - mForegroundServiceController.getAppOps( - sbn.getUser().getIdentifier(), - sbn.getPackageName()); - - entry.mActiveAppOps.clear(); - if (activeOps != null) { - entry.mActiveAppOps.addAll(activeOps); - } - } - }; - - /** * Puts foreground service notifications into its own section. */ private final NotifSection mNotifSection = new NotifSection("ForegroundService") { @@ -230,53 +196,4 @@ public class AppOpsCoordinator implements Coordinator { return false; } }; - - private void onAppOpsChanged(int code, int uid, String packageName, boolean active) { - mMainExecutor.execute(() -> handleAppOpsChanged(code, uid, packageName, active)); - } - - /** - * Update the appOp for the posted notification associated with the current foreground service - * - * @param code code for appOp to add/remove - * @param uid of user the notification is sent to - * @param packageName package that created the notification - * @param active whether the appOpCode is active or not - */ - private void handleAppOpsChanged(int code, int uid, String packageName, boolean active) { - Assert.isMainThread(); - - int userId = UserHandle.getUserId(uid); - - // Update appOps of the app's posted notifications with standard layouts - final ArraySet<String> notifKeys = - mForegroundServiceController.getStandardLayoutKeys(userId, packageName); - if (notifKeys != null) { - boolean changed = false; - for (int i = 0; i < notifKeys.size(); i++) { - final NotificationEntry entry = findNotificationEntryWithKey(notifKeys.valueAt(i)); - if (entry != null - && uid == entry.getSbn().getUid() - && packageName.equals(entry.getSbn().getPackageName())) { - if (active) { - changed |= entry.mActiveAppOps.add(code); - } else { - changed |= entry.mActiveAppOps.remove(code); - } - } - } - if (changed) { - mNotifFilter.invalidateList(); - } - } - } - - private NotificationEntry findNotificationEntryWithKey(String key) { - for (NotificationEntry entry : mNotifPipeline.getAllNotifs()) { - if (entry.getKey().equals(key)) { - return entry; - } - } - return null; - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java index ee2bb6b1d190..3e110671d174 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java @@ -307,7 +307,7 @@ public class PreparationCoordinator implements Coordinator { private void onInflationFinished(NotificationEntry entry) { mLogger.logNotifInflated(entry.getKey()); mInflatingNotifs.remove(entry); - mViewBarn.registerViewForEntry(entry, entry.getRow()); + mViewBarn.registerViewForEntry(entry, entry.getRowController()); mInflationStates.put(entry, STATE_INFLATED); mNotifInflatingFilter.invalidateList(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java index 8849824380d3..f90ec0b4f42a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java @@ -136,6 +136,7 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { .expandableNotificationRow(row) .notificationEntry(entry) .onExpandClickListener(mPresenter) + .listContainer(mListContainer) .build(); ExpandableNotificationRowController rowController = component.getExpandableNotificationRowController(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java index 9782c3ef55fe..1c02c62602cf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java @@ -29,8 +29,7 @@ import com.android.systemui.statusbar.notification.collection.ShadeListBuilder; import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer; import com.android.systemui.statusbar.notification.collection.coordinator.NotifCoordinators; import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; -import com.android.systemui.statusbar.notification.collection.render.NotifViewManager; -import com.android.systemui.statusbar.notification.collection.render.NotifViewManagerBuilder; +import com.android.systemui.statusbar.notification.collection.render.ShadeViewManagerFactory; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import java.io.FileDescriptor; @@ -51,7 +50,7 @@ public class NotifPipelineInitializer implements Dumpable { private final NotifCoordinators mNotifPluggableCoordinators; private final NotifInflaterImpl mNotifInflater; private final DumpManager mDumpManager; - private final NotifViewManagerBuilder mNotifViewManagerBuilder; + private final ShadeViewManagerFactory mShadeViewManagerFactory; private final FeatureFlags mFeatureFlags; @@ -64,7 +63,7 @@ public class NotifPipelineInitializer implements Dumpable { NotifCoordinators notifCoordinators, NotifInflaterImpl notifInflater, DumpManager dumpManager, - NotifViewManagerBuilder notifViewManagerBuilder, + ShadeViewManagerFactory shadeViewManagerFactory, FeatureFlags featureFlags) { mPipelineWrapper = pipelineWrapper; mGroupCoalescer = groupCoalescer; @@ -73,8 +72,8 @@ public class NotifPipelineInitializer implements Dumpable { mNotifPluggableCoordinators = notifCoordinators; mDumpManager = dumpManager; mNotifInflater = notifInflater; + mShadeViewManagerFactory = shadeViewManagerFactory; mFeatureFlags = featureFlags; - mNotifViewManagerBuilder = notifViewManagerBuilder; } /** Hooks the new pipeline up to NotificationManager */ @@ -95,8 +94,7 @@ public class NotifPipelineInitializer implements Dumpable { // Wire up pipeline if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) { - NotifViewManager notifViewManager = mNotifViewManagerBuilder.build(listContainer); - notifViewManager.attach(mListBuilder); + mShadeViewManagerFactory.create(listContainer).attach(mListBuilder); } mListBuilder.attach(mNotifCollection); mNotifCollection.attach(mGroupCoalescer); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeController.kt new file mode 100644 index 000000000000..67f7b1c09df3 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeController.kt @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2020 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.statusbar.notification.collection.render + +import android.view.View +import java.lang.RuntimeException +import java.lang.StringBuilder + +/** + * A controller that represents a single unit of addable/removable view(s) in the notification + * shade. Some nodes are just a single view (such as a header), while some might involve many views + * (such as a notification row). + * + * It's possible for nodes to support having child nodes (for example, some notification rows + * contain other notification rows). If so, they must implement all of the child-related methods + * below. + */ +interface NodeController { + /** A string that uniquely(ish) represents the node in the tree. Used for debugging. */ + val nodeLabel: String + + val view: View + + fun getChildAt(index: Int): View? { + throw RuntimeException("Not supported") + } + + fun getChildCount(): Int { + throw RuntimeException("Not supported") + } + + fun addChildAt(child: NodeController, index: Int) { + throw RuntimeException("Not supported") + } + + fun moveChildTo(child: NodeController, index: Int) { + throw RuntimeException("Not supported") + } + + fun removeChild(child: NodeController, isTransfer: Boolean) { + throw RuntimeException("Not supported") + } +} + +/** + * Used to specify the tree of [NodeController]s that currently make up the shade. + */ +interface NodeSpec { + val parent: NodeSpec? + val controller: NodeController + val children: List<NodeSpec> +} + +class NodeSpecImpl( + override val parent: NodeSpec?, + override val controller: NodeController +) : NodeSpec { + override val children = mutableListOf<NodeSpec>() +} + +/** + * Converts a tree spec to human-readable string, for dumping purposes. + */ +fun treeSpecToStr(tree: NodeSpec): String { + return StringBuilder().also { treeSpecToStrHelper(tree, it, "") }.toString() +} + +private fun treeSpecToStrHelper(tree: NodeSpec, sb: StringBuilder, indent: String) { + sb.append("${indent}ns{${tree.controller.nodeLabel}") + if (tree.children.isNotEmpty()) { + val childIndent = "$indent " + for (child in tree.children) { + treeSpecToStrHelper(child, sb, childIndent) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewBarn.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewBarn.kt index 54000950e3ef..00fd09dd662e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewBarn.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewBarn.kt @@ -18,18 +18,19 @@ package com.android.systemui.statusbar.notification.collection.render import android.view.textclassifier.Log import com.android.systemui.statusbar.notification.collection.ListEntry -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController import javax.inject.Inject import javax.inject.Singleton /** - * The ViewBarn is just a map from [ListEntry] to an instance of an [ExpandableNotificationRow]. + * The ViewBarn is just a map from [ListEntry] to an instance of an + * [ExpandableNotificationRowController]. */ @Singleton class NotifViewBarn @Inject constructor() { - private val rowMap = mutableMapOf<String, ExpandableNotificationRow>() + private val rowMap = mutableMapOf<String, ExpandableNotificationRowController>() - fun requireView(forEntry: ListEntry): ExpandableNotificationRow { + fun requireView(forEntry: ListEntry): ExpandableNotificationRowController { if (DEBUG) { Log.d(TAG, "requireView: $forEntry.key") } @@ -41,11 +42,11 @@ class NotifViewBarn @Inject constructor() { return li } - fun registerViewForEntry(entry: ListEntry, view: ExpandableNotificationRow) { + fun registerViewForEntry(entry: ListEntry, controller: ExpandableNotificationRowController) { if (DEBUG) { Log.d(TAG, "registerViewForEntry: $entry.key") } - rowMap[entry.key] = view + rowMap[entry.key] = controller } fun removeViewForEntry(entry: ListEntry) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewManager.kt deleted file mode 100644 index f2e2c39ab612..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewManager.kt +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright (C) 2020 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.statusbar.notification.collection.render - -import android.annotation.MainThread -import android.view.View -import com.android.systemui.statusbar.notification.collection.GroupEntry -import com.android.systemui.statusbar.notification.collection.GroupEntry.ROOT_ENTRY -import com.android.systemui.statusbar.notification.collection.ListEntry -import com.android.systemui.statusbar.notification.collection.NotificationEntry -import com.android.systemui.statusbar.notification.collection.ShadeListBuilder -import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow -import com.android.systemui.statusbar.notification.stack.NotificationListContainer -import javax.inject.Inject - -/** - * A consumer of a Notification tree built by [ShadeListBuilder] which will update the notification - * presenter with the minimum operations required to make the old tree match the new one - */ -@MainThread -class NotifViewManager constructor( - private val listContainer: NotificationListContainer, - private val viewBarn: NotifViewBarn, - private val logger: NotifViewManagerLogger -) { - private val rootNode = RootWrapper(listContainer) - private val rows = mutableMapOf<ListEntry, RowNode>() - - fun attach(listBuilder: ShadeListBuilder) { - listBuilder.setOnRenderListListener(::onNewNotifTree) - } - - private fun onNewNotifTree(tree: List<ListEntry>) { - // Step 1: Detach all views whose parents have changed - detachRowsWithModifiedParents() - - // Step 2: Attach all new views and reattach all views whose parents changed. - // Also reorder existing children to match the spec we've received - val orderChanged = addAndReorderChildren(rootNode, tree) - if (orderChanged) { - listContainer.generateChildOrderChangedEvent() - } - } - - private fun detachRowsWithModifiedParents() { - val toRemove = mutableListOf<ListEntry>() - for (row in rows.values) { - val oldParentEntry = row.nodeParent?.entry - val newParentEntry = row.entry.parent - - if (newParentEntry != oldParentEntry) { - // If the parent is null, then we should remove the child completely. If not, then - // the parent merely changed: we'll detach it for now and then attach it to the - // new parent in step 2. - val isTransfer = newParentEntry != null - if (!isTransfer) { - toRemove.add(row.entry) - } - - if (!isTransfer && !isAttachedToRootEntry(oldParentEntry)) { - // If our view parent has also been removed (i.e. is no longer attached to the - // root entry) then we skip removing the child here - logger.logSkippingDetach(row.entry.key, row.nodeParent?.entry?.key) - } else { - logger.logDetachingChild( - row.entry.key, - isTransfer, - oldParentEntry?.key, - newParentEntry?.key) - row.nodeParent?.removeChild(row, isTransfer) - row.nodeParent = null - } - } - } - rows.keys.removeAll(toRemove) - } - - private fun addAndReorderChildren(parent: ParentNode, childEntries: List<ListEntry>): Boolean { - var orderChanged = false - for ((index, entry) in childEntries.withIndex()) { - val row = getRowNode(entry) - val currView = parent.getChildViewAt(index) - if (currView != row.view) { - when (row.nodeParent) { - null -> { - logger.logAttachingChild(row.entry.key, parent.entry.key) - parent.addChildAt(row, index) - row.nodeParent = parent - } - parent -> { - logger.logMovingChild(row.entry.key, parent.entry.key, index) - parent.moveChild(row, index) - orderChanged = true - } - else -> { - throw IllegalStateException("Child ${row.entry.key} should have parent " + - "${parent.entry.key} but is actually " + - "${row.nodeParent?.entry?.key}") - } - } - } - if (row is GroupWrapper) { - val childOrderChanged = addAndReorderChildren(row, row.entry.children) - orderChanged = orderChanged || childOrderChanged - } - } - // TODO: setUntruncatedChildCount - - return orderChanged - } - - private fun getRowNode(entry: ListEntry): RowNode { - return rows.getOrPut(entry) { - when (entry) { - is NotificationEntry -> RowWrapper(entry, viewBarn.requireView(entry)) - is GroupEntry -> - GroupWrapper( - entry, - viewBarn.requireView(checkNotNull(entry.summary)), - listContainer) - else -> throw RuntimeException( - "Unexpected entry type for ${entry.key}: ${entry.javaClass}") - } - } - } -} - -class NotifViewManagerBuilder @Inject constructor( - private val viewBarn: NotifViewBarn, - private val logger: NotifViewManagerLogger -) { - fun build(listContainer: NotificationListContainer): NotifViewManager { - return NotifViewManager(listContainer, viewBarn, logger) - } -} - -private fun isAttachedToRootEntry(entry: ListEntry?): Boolean { - return when (entry) { - null -> false - ROOT_ENTRY -> true - else -> isAttachedToRootEntry(entry.parent) - } -} - -private interface Node { - val entry: ListEntry - val nodeParent: ParentNode? -} - -private interface ParentNode : Node { - fun getChildViewAt(index: Int): View? - fun addChildAt(child: RowNode, index: Int) - fun moveChild(child: RowNode, index: Int) - fun removeChild(child: RowNode, isTransfer: Boolean) -} - -private interface RowNode : Node { - val view: ExpandableNotificationRow - override var nodeParent: ParentNode? -} - -private class RootWrapper( - private val listContainer: NotificationListContainer -) : ParentNode { - override val entry: ListEntry = ROOT_ENTRY - override val nodeParent: ParentNode? = null - - override fun getChildViewAt(index: Int): View? { - return listContainer.getContainerChildAt(index) - } - - override fun addChildAt(child: RowNode, index: Int) { - listContainer.addContainerViewAt(child.view, index) - } - - override fun moveChild(child: RowNode, index: Int) { - listContainer.changeViewPosition(child.view, index) - } - - override fun removeChild(child: RowNode, isTransfer: Boolean) { - if (isTransfer) { - listContainer.setChildTransferInProgress(true) - } - listContainer.removeContainerView(child.view) - if (isTransfer) { - listContainer.setChildTransferInProgress(false) - } - } -} - -private class GroupWrapper( - override val entry: GroupEntry, - override val view: ExpandableNotificationRow, - val listContainer: NotificationListContainer -) : RowNode, ParentNode { - - override var nodeParent: ParentNode? = null - - override fun getChildViewAt(index: Int): View? { - return view.getChildNotificationAt(index) - } - - override fun addChildAt(child: RowNode, index: Int) { - view.addChildNotification(child.view, index) - listContainer.notifyGroupChildAdded(child.view) - } - - override fun moveChild(child: RowNode, index: Int) { - view.removeChildNotification(child.view) - view.addChildNotification(child.view, index) - } - - override fun removeChild(child: RowNode, isTransfer: Boolean) { - view.removeChildNotification(child.view) - if (isTransfer) { - listContainer.notifyGroupChildRemoved(child.view, view) - } - } -} - -private class RowWrapper( - override val entry: NotificationEntry, - override val view: ExpandableNotificationRow -) : RowNode { - override var nodeParent: ParentNode? = null -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RootNodeController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RootNodeController.kt new file mode 100644 index 000000000000..e8124944bcb0 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RootNodeController.kt @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2020 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.statusbar.notification.collection.render + +import android.view.View +import com.android.systemui.statusbar.notification.row.ExpandableView +import com.android.systemui.statusbar.notification.stack.NotificationListContainer + +/** + * Temporary wrapper around [NotificationListContainer], for use by [ShadeViewDiffer]. Long term, + * we should just modify NLC to implement the NodeController interface. + */ +class RootNodeController( + private val listContainer: NotificationListContainer +) : NodeController { + override val nodeLabel: String = "<root>" + override val view: View = listContainer as View + + override fun getChildAt(index: Int): View? { + return listContainer.getContainerChildAt(index) + } + + override fun getChildCount(): Int { + return listContainer.containerChildCount + } + + override fun addChildAt(child: NodeController, index: Int) { + listContainer.addContainerViewAt(child.view, index) + } + + override fun moveChildTo(child: NodeController, index: Int) { + listContainer.changeViewPosition(child.view as ExpandableView, index) + } + + override fun removeChild(child: NodeController, isTransfer: Boolean) { + if (isTransfer) { + listContainer.setChildTransferInProgress(true) + } + listContainer.removeContainerView(child.view) + if (isTransfer) { + listContainer.setChildTransferInProgress(false) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt new file mode 100644 index 000000000000..019520f18982 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2020 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.statusbar.notification.collection.render + +import android.annotation.MainThread +import android.view.View +import com.android.systemui.util.kotlin.transform + +/** + * Given a "spec" that describes a "tree" of views, adds and removes views from the + * [rootController] and its children until the actual tree matches the spec. + * + * Every node in the spec tree must specify both a view and its associated [NodeController]. + * Commands to add/remove/reorder children are sent to the controller. How the controller + * interprets these commands is left to its own discretion -- it might add them directly to its + * associated view or to some subview container. + * + * It's possible for nodes to mix "unmanaged" views in alongside managed ones within the same + * container. In this case, whenever the differ runs it will move all unmanaged views to the end + * of the node's child list. + */ +@MainThread +class ShadeViewDiffer( + rootController: NodeController, + private val logger: ShadeViewDifferLogger +) { + private val rootNode = ShadeNode(rootController) + private val nodes = mutableMapOf(rootController to rootNode) + private val views = mutableMapOf<View, ShadeNode>() + + /** + * Adds and removes views from the root (and its children) until their structure matches the + * provided [spec]. The root node of the spec must match the root controller passed to the + * differ's constructor. + */ + fun applySpec(spec: NodeSpec) { + val specMap = treeToMap(spec) + + if (spec.controller != rootNode.controller) { + throw IllegalArgumentException("Tree root ${spec.controller.nodeLabel} does not " + + "match own root at ${rootNode.label}") + } + + detachChildren(rootNode, specMap) + attachChildren(rootNode, specMap) + } + + /** + * If [view] is managed by this differ, then returns the label of the view's controller. + * Otherwise returns View.toString(). + * + * For debugging purposes. + */ + fun getViewLabel(view: View): String { + return views[view]?.label ?: view.toString() + } + + private fun detachChildren( + parentNode: ShadeNode, + specMap: Map<NodeController, NodeSpec> + ) { + val parentSpec = specMap[parentNode.controller] + + for (i in parentNode.getChildCount() - 1 downTo 0) { + val childView = parentNode.getChildAt(i) + views[childView]?.let { childNode -> + val childSpec = specMap[childNode.controller] + + maybeDetachChild(parentNode, parentSpec, childNode, childSpec) + + if (childNode.controller.getChildCount() > 0) { + detachChildren(childNode, specMap) + } + } + } + } + + private fun maybeDetachChild( + parentNode: ShadeNode, + parentSpec: NodeSpec?, + childNode: ShadeNode, + childSpec: NodeSpec? + ) { + val newParentNode = transform(childSpec?.parent) { getNode(it) } + + if (newParentNode != parentNode) { + val childCompletelyRemoved = newParentNode == null + + if (childCompletelyRemoved) { + nodes.remove(childNode.controller) + views.remove(childNode.controller.view) + } + + if (childCompletelyRemoved && parentSpec == null) { + // If both the child and the parent are being removed at the same time, then + // keep the child attached to the parent for animation purposes + logger.logSkippingDetach(childNode.label, parentNode.label) + } else { + logger.logDetachingChild( + childNode.label, + !childCompletelyRemoved, + parentNode.label, + newParentNode?.label) + parentNode.removeChild(childNode, !childCompletelyRemoved) + childNode.parent = null + } + } + } + + private fun attachChildren( + parentNode: ShadeNode, + specMap: Map<NodeController, NodeSpec> + ) { + val parentSpec = checkNotNull(specMap[parentNode.controller]) + + for ((index, childSpec) in parentSpec.children.withIndex()) { + val currView = parentNode.getChildAt(index) + val childNode = getNode(childSpec) + + if (childNode.view != currView) { + + when (childNode.parent) { + null -> { + // A new child (either newly created or coming from some other parent) + logger.logAttachingChild(childNode.label, parentNode.label) + parentNode.addChildAt(childNode, index) + childNode.parent = parentNode + } + parentNode -> { + // A pre-existing child, just in the wrong position. Move it into place + logger.logMovingChild(childNode.label, parentNode.label, index) + parentNode.moveChildTo(childNode, index) + } + else -> { + // Error: child still has a parent. We should have detached it in the + // previous step. + throw IllegalStateException("Child ${childNode.label} should have " + + "parent ${parentNode.label} but is actually " + + "${childNode.parent?.label}") + } + } + } + + if (childSpec.children.isNotEmpty()) { + attachChildren(childNode, specMap) + } + } + } + + private fun getNode(spec: NodeSpec): ShadeNode { + var node = nodes[spec.controller] + if (node == null) { + node = ShadeNode(spec.controller) + nodes[node.controller] = node + views[node.view] = node + } + return node + } + + private fun treeToMap(tree: NodeSpec): Map<NodeController, NodeSpec> { + val map = mutableMapOf<NodeController, NodeSpec>() + + registerNodes(tree, map) + + return map + } + + private fun registerNodes(node: NodeSpec, map: MutableMap<NodeController, NodeSpec>) { + if (map.containsKey(node.controller)) { + throw RuntimeException("Node ${node.controller.nodeLabel} appears more than once") + } + map[node.controller] = node + + if (node.children.isNotEmpty()) { + for (child in node.children) { + registerNodes(child, map) + } + } + } +} + +private class ShadeNode( + val controller: NodeController +) { + val view = controller.view + + var parent: ShadeNode? = null + + val label: String + get() = controller.nodeLabel + + fun getChildAt(index: Int): View? = controller.getChildAt(index) + + fun getChildCount(): Int = controller.getChildCount() + + fun addChildAt(child: ShadeNode, index: Int) { + controller.addChildAt(child.controller, index) + } + + fun moveChildTo(child: ShadeNode, index: Int) { + controller.moveChildTo(child.controller, index) + } + + fun removeChild(child: ShadeNode, isTransfer: Boolean) { + controller.removeChild(child.controller, isTransfer) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewManagerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferLogger.kt index 3d561264d367..19e156f572d4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewManagerLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferLogger.kt @@ -21,7 +21,7 @@ import com.android.systemui.log.LogLevel import com.android.systemui.log.dagger.NotificationLog import javax.inject.Inject -class NotifViewManagerLogger @Inject constructor( +class ShadeViewDifferLogger @Inject constructor( @NotificationLog private val buffer: LogBuffer ) { fun logDetachingChild( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt new file mode 100644 index 000000000000..201be59d80b4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2020 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.statusbar.notification.collection.render + +import com.android.systemui.statusbar.notification.collection.GroupEntry +import com.android.systemui.statusbar.notification.collection.ListEntry +import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.statusbar.notification.collection.ShadeListBuilder +import com.android.systemui.statusbar.notification.stack.NotificationListContainer +import java.lang.RuntimeException +import javax.inject.Inject + +/** + * Responsible for building and applying the "shade node spec": the list (tree) of things that + * currently populate the notification shade. + */ +class ShadeViewManager constructor( + listContainer: NotificationListContainer, + logger: ShadeViewDifferLogger, + private val viewBarn: NotifViewBarn +) { + private val rootController = RootNodeController(listContainer) + private val viewDiffer = ShadeViewDiffer(rootController, logger) + + fun attach(listBuilder: ShadeListBuilder) { + listBuilder.setOnRenderListListener(::onNewNotifTree) + } + + private fun onNewNotifTree(tree: List<ListEntry>) { + viewDiffer.applySpec(buildTree(tree)) + } + + private fun buildTree(notifList: List<ListEntry>): NodeSpec { + val root = NodeSpecImpl(null, rootController) + + for (entry in notifList) { + // TODO: Add section header logic here + root.children.add(buildNotifNode(entry, root)) + } + + return root + } + + private fun buildNotifNode(entry: ListEntry, parent: NodeSpec): NodeSpec { + return when (entry) { + is NotificationEntry -> { + NodeSpecImpl(parent, viewBarn.requireView(entry)) + } + is GroupEntry -> { + val groupNode = NodeSpecImpl( + parent, + viewBarn.requireView(checkNotNull(entry.summary))) + + for (childEntry in entry.children) { + groupNode.children.add(buildNotifNode(childEntry, groupNode)) + } + + groupNode + } + else -> { + throw RuntimeException("Unexpected entry: $entry") + } + } + } +} + +class ShadeViewManagerFactory @Inject constructor( + private val logger: ShadeViewDifferLogger, + private val viewBarn: NotifViewBarn +) { + fun create(listContainer: NotificationListContainer): ShadeViewManager { + return ShadeViewManager(listContainer, logger, viewBarn) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AppOpsInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AppOpsInfo.java deleted file mode 100644 index 28c53dc6d9b2..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AppOpsInfo.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (C) 2018 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.statusbar.notification.row; - -import android.app.AppOpsManager; -import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.graphics.drawable.Drawable; -import android.service.notification.StatusBarNotification; -import android.util.ArraySet; -import android.util.AttributeSet; -import android.view.View; -import android.view.accessibility.AccessibilityEvent; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; - -import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.UiEventLogger; -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.systemui.R; - -/** - * The guts of a notification revealed when performing a long press. - */ -public class AppOpsInfo extends LinearLayout implements NotificationGuts.GutsContent { - private static final String TAG = "AppOpsGuts"; - - private PackageManager mPm; - - private String mPkg; - private String mAppName; - private int mAppUid; - private StatusBarNotification mSbn; - private ArraySet<Integer> mAppOps; - private MetricsLogger mMetricsLogger; - private OnSettingsClickListener mOnSettingsClickListener; - private NotificationGuts mGutsContainer; - private UiEventLogger mUiEventLogger; - - private OnClickListener mOnOk = v -> { - mGutsContainer.closeControls(v, false); - }; - - public AppOpsInfo(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public interface OnSettingsClickListener { - void onClick(View v, String pkg, int uid, ArraySet<Integer> ops); - } - - public void bindGuts(final PackageManager pm, - final OnSettingsClickListener onSettingsClick, - final StatusBarNotification sbn, - final UiEventLogger uiEventLogger, - ArraySet<Integer> activeOps) { - mPkg = sbn.getPackageName(); - mSbn = sbn; - mPm = pm; - mAppName = mPkg; - mOnSettingsClickListener = onSettingsClick; - mAppOps = activeOps; - mUiEventLogger = uiEventLogger; - - bindHeader(); - bindPrompt(); - bindButtons(); - - logUiEvent(NotificationAppOpsEvent.NOTIFICATION_APP_OPS_OPEN); - mMetricsLogger = new MetricsLogger(); - mMetricsLogger.visibility(MetricsEvent.APP_OPS_GUTS, true); - } - - private void bindHeader() { - // Package name - Drawable pkgicon = null; - ApplicationInfo info; - try { - info = mPm.getApplicationInfo(mPkg, - PackageManager.MATCH_UNINSTALLED_PACKAGES - | PackageManager.MATCH_DISABLED_COMPONENTS - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE - | PackageManager.MATCH_DIRECT_BOOT_AWARE); - if (info != null) { - mAppUid = mSbn.getUid(); - mAppName = String.valueOf(mPm.getApplicationLabel(info)); - pkgicon = mPm.getApplicationIcon(info); - } - } catch (PackageManager.NameNotFoundException e) { - // app is gone, just show package name and generic icon - pkgicon = mPm.getDefaultActivityIcon(); - } - ((ImageView) findViewById(R.id.pkgicon)).setImageDrawable(pkgicon); - ((TextView) findViewById(R.id.pkgname)).setText(mAppName); - } - - private void bindPrompt() { - final TextView prompt = findViewById(R.id.prompt); - prompt.setText(getPrompt()); - } - - private void bindButtons() { - View settings = findViewById(R.id.settings); - settings.setOnClickListener((View view) -> { - mOnSettingsClickListener.onClick(view, mPkg, mAppUid, mAppOps); - }); - TextView ok = findViewById(R.id.ok); - ok.setOnClickListener(mOnOk); - ok.setAccessibilityDelegate(mGutsContainer.getAccessibilityDelegate()); - } - - private String getPrompt() { - if (mAppOps == null || mAppOps.size() == 0) { - return ""; - } else if (mAppOps.size() == 1) { - if (mAppOps.contains(AppOpsManager.OP_CAMERA)) { - return mContext.getString(R.string.appops_camera); - } else if (mAppOps.contains(AppOpsManager.OP_RECORD_AUDIO)) { - return mContext.getString(R.string.appops_microphone); - } else { - return mContext.getString(R.string.appops_overlay); - } - } else if (mAppOps.size() == 2) { - if (mAppOps.contains(AppOpsManager.OP_CAMERA)) { - if (mAppOps.contains(AppOpsManager.OP_RECORD_AUDIO)) { - return mContext.getString(R.string.appops_camera_mic); - } else { - return mContext.getString(R.string.appops_camera_overlay); - } - } else { - return mContext.getString(R.string.appops_mic_overlay); - } - } else { - return mContext.getString(R.string.appops_camera_mic_overlay); - } - } - - @Override - public void onInitializeAccessibilityEvent(AccessibilityEvent event) { - super.onInitializeAccessibilityEvent(event); - if (mGutsContainer != null && - event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { - if (mGutsContainer.isExposed()) { - event.getText().add(mContext.getString( - R.string.notification_channel_controls_opened_accessibility, mAppName)); - } else { - event.getText().add(mContext.getString( - R.string.notification_channel_controls_closed_accessibility, mAppName)); - } - } - } - - @Override - public void setGutsParent(NotificationGuts guts) { - mGutsContainer = guts; - } - - @Override - public boolean willBeRemoved() { - return false; - } - - @Override - public boolean shouldBeSaved() { - return false; - } - - @Override - public boolean needsFalsingProtection() { - return false; - } - - @Override - public View getContentView() { - return this; - } - - @Override - public boolean handleCloseControls(boolean save, boolean force) { - logUiEvent(NotificationAppOpsEvent.NOTIFICATION_APP_OPS_CLOSE); - if (mMetricsLogger != null) { - mMetricsLogger.visibility(MetricsEvent.APP_OPS_GUTS, false); - } - return false; - } - - @Override - public int getActualHeight() { - return getHeight(); - } - - private void logUiEvent(NotificationAppOpsEvent event) { - if (mSbn != null) { - mUiEventLogger.logWithInstanceId(event, - mSbn.getUid(), mSbn.getPackageName(), mSbn.getInstanceId()); - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 22d0357b14c2..d7fa54f0091d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -239,7 +239,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView private boolean mShowNoBackground; private ExpandableNotificationRow mNotificationParent; private OnExpandClickListener mOnExpandClickListener; - private View.OnClickListener mOnAppOpsClickListener; + private View.OnClickListener mOnAppClickListener; private View.OnClickListener mOnFeedbackClickListener; // Listener will be called when receiving a long click event. @@ -1139,7 +1139,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView items.add(NotificationMenuRow.createPartialConversationItem(mContext)); items.add(NotificationMenuRow.createInfoItem(mContext)); items.add(NotificationMenuRow.createSnoozeItem(mContext)); - items.add(NotificationMenuRow.createAppOpsItem(mContext)); mMenuRow.setMenuItems(items); } if (existed) { @@ -1598,7 +1597,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView RowContentBindStage rowContentBindStage, OnExpandClickListener onExpandClickListener, NotificationMediaManager notificationMediaManager, - CoordinateOnClickListener onAppOpsClickListener, CoordinateOnClickListener onFeedbackClickListener, FalsingManager falsingManager, StatusBarStateController statusBarStateController, @@ -1619,7 +1617,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mRowContentBindStage = rowContentBindStage; mOnExpandClickListener = onExpandClickListener; mMediaManager = notificationMediaManager; - setAppOpsOnClickListener(onAppOpsClickListener); setOnFeedbackClickListener(onFeedbackClickListener); mFalsingManager = falsingManager; mStatusbarStateController = statusBarStateController; @@ -1677,14 +1674,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView requestLayout(); } - public void showAppOpsIcons(ArraySet<Integer> activeOps) { - if (mIsSummaryWithChildren) { - mChildrenContainer.showAppOpsIcons(activeOps); - } - mPrivateLayout.showAppOpsIcons(activeOps); - mPublicLayout.showAppOpsIcons(activeOps); - } - public void showFeedbackIcon(boolean show) { if (mIsSummaryWithChildren) { mChildrenContainer.showFeedbackIcon(show); @@ -1721,24 +1710,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mPublicLayout.setRecentlyAudiblyAlerted(audiblyAlertedRecently); } - public View.OnClickListener getAppOpsOnClickListener() { - return mOnAppOpsClickListener; - } - - void setAppOpsOnClickListener(CoordinateOnClickListener l) { - mOnAppOpsClickListener = v -> { - createMenu(); - NotificationMenuRowPlugin provider = getProvider(); - if (provider == null) { - return; - } - MenuItem menuItem = provider.getAppOpsMenuItem(mContext); - if (menuItem != null) { - l.onClick(this, v.getWidth() / 2, v.getHeight() / 2, menuItem); - } - }; - } - public View.OnClickListener getFeedbackOnClickListener() { return mOnFeedbackClickListener; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java index 86a3271c4eac..690dce915cf3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java @@ -22,21 +22,27 @@ import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENAB import android.view.View; import android.view.ViewGroup; +import androidx.annotation.NonNull; + import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.statusbar.NotificationMediaManager; +import com.android.systemui.statusbar.notification.collection.render.NodeController; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; import com.android.systemui.statusbar.notification.row.dagger.AppName; import com.android.systemui.statusbar.notification.row.dagger.NotificationKey; import com.android.systemui.statusbar.notification.row.dagger.NotificationRowScope; +import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.util.time.SystemClock; +import java.util.List; + import javax.inject.Inject; import javax.inject.Named; @@ -44,8 +50,9 @@ import javax.inject.Named; * Controller for {@link ExpandableNotificationRow}. */ @NotificationRowScope -public class ExpandableNotificationRowController { +public class ExpandableNotificationRowController implements NodeController { private final ExpandableNotificationRow mView; + private final NotificationListContainer mListContainer; private final ActivatableNotificationViewController mActivatableNotificationViewController; private final NotificationMediaManager mMediaManager; private final PluginManager mPluginManager; @@ -62,7 +69,6 @@ public class ExpandableNotificationRowController { private final ExpandableNotificationRow.ExpansionLogger mExpansionLogger = this::logNotificationExpansion; - private final ExpandableNotificationRow.CoordinateOnClickListener mOnAppOpsClickListener; private final ExpandableNotificationRow.CoordinateOnClickListener mOnFeedbackClickListener; private final NotificationGutsManager mNotificationGutsManager; private final OnDismissCallback mOnDismissCallback; @@ -72,6 +78,7 @@ public class ExpandableNotificationRowController { @Inject public ExpandableNotificationRowController(ExpandableNotificationRow view, + NotificationListContainer listContainer, ActivatableNotificationViewController activatableNotificationViewController, NotificationMediaManager mediaManager, PluginManager pluginManager, SystemClock clock, @AppName String appName, @NotificationKey String notificationKey, @@ -86,6 +93,7 @@ public class ExpandableNotificationRowController { OnDismissCallback onDismissCallback, FalsingManager falsingManager, PeopleNotificationIdentifier peopleNotificationIdentifier) { mView = view; + mListContainer = listContainer; mActivatableNotificationViewController = activatableNotificationViewController; mMediaManager = mediaManager; mPluginManager = pluginManager; @@ -101,7 +109,6 @@ public class ExpandableNotificationRowController { mStatusBarStateController = statusBarStateController; mNotificationGutsManager = notificationGutsManager; mOnDismissCallback = onDismissCallback; - mOnAppOpsClickListener = mNotificationGutsManager::openGuts; mOnFeedbackClickListener = mNotificationGutsManager::openGuts; mAllowLongPress = allowLongPress; mFalsingManager = falsingManager; @@ -123,7 +130,6 @@ public class ExpandableNotificationRowController { mRowContentBindStage, mOnExpandClickListener, mMediaManager, - mOnAppOpsClickListener, mOnFeedbackClickListener, mFalsingManager, mStatusBarStateController, @@ -162,4 +168,52 @@ public class ExpandableNotificationRowController { private void logNotificationExpansion(String key, boolean userAction, boolean expanded) { mNotificationLogger.onExpansionChanged(key, userAction, expanded); } + + @Override + @NonNull + public String getNodeLabel() { + return mView.getEntry().getKey(); + } + + @Override + @NonNull + public View getView() { + return mView; + } + + @Override + public View getChildAt(int index) { + return mView.getChildNotificationAt(index); + } + + @Override + public void addChildAt(NodeController child, int index) { + ExpandableNotificationRow childView = (ExpandableNotificationRow) child.getView(); + + mView.addChildNotification((ExpandableNotificationRow) child.getView()); + mListContainer.notifyGroupChildAdded(childView); + } + + @Override + public void moveChildTo(NodeController child, int index) { + ExpandableNotificationRow childView = (ExpandableNotificationRow) child.getView(); + mView.removeChildNotification(childView); + mView.addChildNotification(childView, index); + } + + @Override + public void removeChild(NodeController child, boolean isTransfer) { + ExpandableNotificationRow childView = (ExpandableNotificationRow) child.getView(); + + mView.removeChildNotification(childView); + if (!isTransfer) { + mListContainer.notifyGroupChildRemoved(childView, mView); + } + } + + @Override + public int getChildCount() { + final List<ExpandableNotificationRow> mChildren = mView.getAttachedChildren(); + return mChildren != null ? mChildren.size() : 0; + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java index 2986b9b75b98..c7e44c5e8e0a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java @@ -1568,18 +1568,6 @@ public class NotificationContentView extends FrameLayout { return header; } - public void showAppOpsIcons(ArraySet<Integer> activeOps) { - if (mContractedChild != null) { - mContractedWrapper.showAppOpsIcons(activeOps); - } - if (mExpandedChild != null) { - mExpandedWrapper.showAppOpsIcons(activeOps); - } - if (mHeadsUpChild != null) { - mHeadsUpWrapper.showAppOpsIcons(activeOps); - } - } - public void showFeedbackIcon(boolean show) { if (mContractedChild != null) { mContractedWrapper.showFeedbackIcon(show); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java index 729b131ac553..05d44f6eb406 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java @@ -268,8 +268,6 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx try { if (gutsView instanceof NotificationSnooze) { initializeSnoozeView(row, (NotificationSnooze) gutsView); - } else if (gutsView instanceof AppOpsInfo) { - initializeAppOpsInfo(row, (AppOpsInfo) gutsView); } else if (gutsView instanceof NotificationInfo) { initializeNotificationInfo(row, (NotificationInfo) gutsView); } else if (gutsView instanceof NotificationConversationInfo) { @@ -309,36 +307,6 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx } /** - * Sets up the {@link AppOpsInfo} inside the notification row's guts. - * - * @param row view to set up the guts for - * @param appOpsInfoView view to set up/bind within {@code row} - */ - private void initializeAppOpsInfo( - final ExpandableNotificationRow row, - AppOpsInfo appOpsInfoView) { - NotificationGuts guts = row.getGuts(); - StatusBarNotification sbn = row.getEntry().getSbn(); - UserHandle userHandle = sbn.getUser(); - PackageManager pmUser = StatusBar.getPackageManagerForUser(mContext, - userHandle.getIdentifier()); - - AppOpsInfo.OnSettingsClickListener onSettingsClick = - (View v, String pkg, int uid, ArraySet<Integer> ops) -> { - mUiEventLogger.logWithInstanceId( - NotificationAppOpsEvent.NOTIFICATION_APP_OPS_SETTINGS_CLICK, - sbn.getUid(), sbn.getPackageName(), sbn.getInstanceId()); - mMetricsLogger.action(MetricsProto.MetricsEvent.ACTION_OPS_GUTS_SETTINGS); - guts.resetFalsingCheck(); - startAppOpsSettingsActivity(pkg, uid, ops, row); - }; - if (!row.getEntry().mActiveAppOps.isEmpty()) { - appOpsInfoView.bindGuts(pmUser, onSettingsClick, sbn, mUiEventLogger, - row.getEntry().mActiveAppOps); - } - } - - /** * Sets up the {@link FeedbackInfo} inside the notification row's guts. * * @param row view to set up the guts for diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java index d264af94947d..205cecc92e55 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java @@ -76,7 +76,6 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl private Context mContext; private FrameLayout mMenuContainer; private NotificationMenuItem mInfoItem; - private MenuItem mAppOpsItem; private MenuItem mFeedbackItem; private MenuItem mSnoozeItem; private ArrayList<MenuItem> mLeftMenuItems; @@ -138,11 +137,6 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl } @Override - public MenuItem getAppOpsMenuItem(Context context) { - return mAppOpsItem; - } - - @Override public MenuItem getFeedbackMenuItem(Context context) { return mFeedbackItem; } @@ -264,7 +258,6 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl // Only show snooze for non-foreground notifications, and if the setting is on mSnoozeItem = createSnoozeItem(mContext); } - mAppOpsItem = createAppOpsItem(mContext); mFeedbackItem = createFeedbackItem(mContext); NotificationEntry entry = mParent.getEntry(); int personNotifType = mPeopleNotificationIdentifier @@ -281,7 +274,6 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl mRightMenuItems.add(mSnoozeItem); } mRightMenuItems.add(mInfoItem); - mRightMenuItems.add(mAppOpsItem); mRightMenuItems.add(mFeedbackItem); mLeftMenuItems.addAll(mRightMenuItems); @@ -690,14 +682,6 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl R.drawable.ic_settings); } - static MenuItem createAppOpsItem(Context context) { - AppOpsInfo appOpsContent = (AppOpsInfo) LayoutInflater.from(context).inflate( - R.layout.app_ops_info, null, false); - MenuItem info = new NotificationMenuItem(context, null, appOpsContent, - -1 /*don't show in slow swipe menu */); - return info; - } - static MenuItem createFeedbackItem(Context context) { FeedbackInfo feedbackContent = (FeedbackInfo) LayoutInflater.from(context).inflate( R.layout.feedback_info, null, false); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java index 28ddf5971bcb..becc9a772b28 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java @@ -25,6 +25,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController; +import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.phone.StatusBar; import dagger.Binds; @@ -55,6 +56,8 @@ public interface ExpandableNotificationRowComponent { Builder notificationEntry(NotificationEntry entry); @BindsInstance Builder onExpandClickListener(ExpandableNotificationRow.OnExpandClickListener presenter); + @BindsInstance + Builder listContainer(NotificationListContainer listContainer); ExpandableNotificationRowComponent build(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java index 46517711a0dc..3f5867477f16 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java @@ -18,7 +18,6 @@ package com.android.systemui.statusbar.notification.row.wrapper; import static com.android.systemui.statusbar.notification.TransformState.TRANSFORM_Y; -import android.app.AppOpsManager; import android.app.Notification; import android.content.Context; import android.util.ArraySet; @@ -64,10 +63,6 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper { private TextView mHeaderText; private TextView mAppNameText; private ImageView mWorkProfileImage; - private View mCameraIcon; - private View mMicIcon; - private View mOverlayIcon; - private View mAppOps; private View mAudiblyAlertedIcon; private FrameLayout mIconContainer; private View mFeedbackIcon; @@ -109,7 +104,6 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper { } }, TRANSFORMING_VIEW_TITLE); resolveHeaderViews(); - addAppOpsOnClickListener(row); addFeedbackOnClickListener(row); } @@ -121,10 +115,6 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper { mExpandButton = mView.findViewById(com.android.internal.R.id.expand_button); mWorkProfileImage = mView.findViewById(com.android.internal.R.id.profile_badge); mNotificationHeader = mView.findViewById(com.android.internal.R.id.notification_header); - mCameraIcon = mView.findViewById(com.android.internal.R.id.camera); - mMicIcon = mView.findViewById(com.android.internal.R.id.mic); - mOverlayIcon = mView.findViewById(com.android.internal.R.id.overlay); - mAppOps = mView.findViewById(com.android.internal.R.id.app_ops); mAudiblyAlertedIcon = mView.findViewById(com.android.internal.R.id.alerted_icon); mFeedbackIcon = mView.findViewById(com.android.internal.R.id.feedback); if (mNotificationHeader != null) { @@ -133,38 +123,6 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper { } } - private void addAppOpsOnClickListener(ExpandableNotificationRow row) { - View.OnClickListener listener = row.getAppOpsOnClickListener(); - if (mNotificationHeader != null) { - mNotificationHeader.setAppOpsOnClickListener(listener); - } - if (mAppOps != null) { - mAppOps.setOnClickListener(listener); - } - } - - /** - * Shows or hides 'app op in use' icons based on app usage. - */ - @Override - public void showAppOpsIcons(ArraySet<Integer> appOps) { - if (appOps == null) { - return; - } - if (mOverlayIcon != null) { - mOverlayIcon.setVisibility(appOps.contains(AppOpsManager.OP_SYSTEM_ALERT_WINDOW) - ? View.VISIBLE : View.GONE); - } - if (mCameraIcon != null) { - mCameraIcon.setVisibility(appOps.contains(AppOpsManager.OP_CAMERA) - ? View.VISIBLE : View.GONE); - } - if (mMicIcon != null) { - mMicIcon.setVisibility(appOps.contains(AppOpsManager.OP_RECORD_AUDIO) - ? View.VISIBLE : View.GONE); - } - } - private void addFeedbackOnClickListener(ExpandableNotificationRow row) { View.OnClickListener listener = row.getFeedbackOnClickListener(); if (mNotificationHeader != null) { @@ -304,15 +262,6 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper { mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TITLE, mHeaderText); } - if (mCameraIcon != null) { - mTransformationHelper.addViewTransformingToSimilar(mCameraIcon); - } - if (mMicIcon != null) { - mTransformationHelper.addViewTransformingToSimilar(mMicIcon); - } - if (mOverlayIcon != null) { - mTransformationHelper.addViewTransformingToSimilar(mOverlayIcon); - } if (mAudiblyAlertedIcon != null) { mTransformationHelper.addViewTransformingToSimilar(mAudiblyAlertedIcon); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java index 605fbc0f6125..42f5e389d5a8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java @@ -97,14 +97,6 @@ public abstract class NotificationViewWrapper implements TransformableView { } /** - * Show a set of app opp icons in the layout. - * - * @param appOps which app ops to show - */ - public void showAppOpsIcons(ArraySet<Integer> appOps) { - } - - /** * Shows or hides feedback icon. */ public void showFeedbackIcon(boolean show) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java index 93c2377ccfae..7e4266c7cd28 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java @@ -1303,20 +1303,6 @@ public class NotificationChildrenContainer extends ViewGroup { } /** - * Show a set of app opp icons in the layout. - * - * @param appOps which app ops to show - */ - public void showAppOpsIcons(ArraySet<Integer> appOps) { - if (mNotificationHeaderWrapper != null) { - mNotificationHeaderWrapper.showAppOpsIcons(appOps); - } - if (mNotificationHeaderWrapperLowPriority != null) { - mNotificationHeaderWrapperLowPriority.showAppOpsIcons(appOps); - } - } - - /** * Shows or hides feedback icon. */ public void showFeedbackIcon(boolean show) { 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 2ff67abd6377..d2f8a39cc8fb 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 @@ -180,8 +180,7 @@ import javax.inject.Named; * A layout which handles a dynamic amount of notifications and presents them in a scrollable stack. */ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAdapter, - NotificationListContainer, ConfigurationListener, Dumpable, - DynamicPrivacyController.Listener { + ConfigurationListener, Dumpable, DynamicPrivacyController.Listener { public static final float BACKGROUND_ALPHA_DIMMED = 0.7f; private static final String TAG = "StackScroller"; @@ -213,6 +212,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd private float mExpandedHeight; private int mOwnScrollY; + private View mScrollAnchorView; private int mScrollAnchorViewY; private int mMaxLayoutHeight; @@ -545,6 +545,19 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd updateDecorViews(useDarkText); }; + private final ExpandableView.OnHeightChangedListener mOnChildHeightChangedListener = + new ExpandableView.OnHeightChangedListener() { + @Override + public void onHeightChanged(ExpandableView view, boolean needsAnimation) { + onChildHeightChanged(view, needsAnimation); + } + + @Override + public void onReset(ExpandableView view) { + onChildHeightReset(view); + } + }; + @Inject public NotificationStackScrollLayout( @Named(VIEW_CONTEXT) Context context, @@ -576,7 +589,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd mLockscreenUserManager = notificationLockscreenUserManager; mNotificationGutsManager = notificationGutsManager; mHeadsUpManager = headsUpManager; - mHeadsUpManager.addListener(mRoundnessManager); mHeadsUpManager.setAnimationStateHandler(this::setHeadsUpGoingAwayAnimationsAllowed); mKeyguardBypassController = keyguardBypassController; mFalsingManager = falsingManager; @@ -608,9 +620,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd res.getBoolean(R.bool.config_drawNotificationBackground); mFadeNotificationsOnDismiss = res.getBoolean(R.bool.config_fadeNotificationsOnDismiss); - mRoundnessManager.setAnimatedChildren(mChildrenToAddAnimated); - mRoundnessManager.setOnRoundingChangedCallback(this::invalidate); - addOnExpandedHeightChangedListener(mRoundnessManager::setExpanded); mLockscreenUserManager.addUserChangedListener(mLockscreenUserChangeListener); setOutlineProvider(mOutlineProvider); @@ -637,13 +646,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd tunerService.addTunable((key, newValue) -> { if (key.equals(HIGH_PRIORITY)) { mHighPriorityBeforeSpeedBump = "1".equals(newValue); - } else if (key.equals(Settings.Secure.NOTIFICATION_DISMISS_RTL)) { - updateDismissRtlSetting("1".equals(newValue)); - } else if (key.equals(Settings.Secure.NOTIFICATION_HISTORY_ENABLED)) { - updateFooter(); } - }, HIGH_PRIORITY, Settings.Secure.NOTIFICATION_DISMISS_RTL, - Settings.Secure.NOTIFICATION_HISTORY_ENABLED); + }, HIGH_PRIORITY); mFeatureFlags = featureFlags; mNotifPipeline = notifPipeline; @@ -693,7 +697,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } } - private void updateDismissRtlSetting(boolean dismissRtl) { + void updateDismissRtlSetting(boolean dismissRtl) { mDismissRtl = dismissRtl; for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); @@ -834,7 +838,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd Dependency.get(ConfigurationController.class).removeCallback(this); } - @Override @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public NotificationSwipeActionHelper getSwipeActionHelper() { return mSwipeHelper; @@ -1150,14 +1153,16 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd mNoAmbient = noAmbient; } - @Override @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) public void setChildLocationsChangedListener( NotificationLogger.OnChildLocationsChangedListener listener) { mListener = listener; } - @Override + public void setScrollAnchorView(View scrollAnchorView) { + mScrollAnchorView = scrollAnchorView; + } + @ShadeViewRefactor(RefactorComponent.LAYOUT_ALGORITHM) public boolean isInVisibleLocation(NotificationEntry entry) { ExpandableNotificationRow row = entry.getRow(); @@ -1856,7 +1861,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } } - @Override @ShadeViewRefactor(RefactorComponent.ADAPTER) public ViewGroup getViewParentForNotification(NotificationEntry entry) { return this; @@ -2546,7 +2550,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd previous); } - @Override @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public boolean hasPulsingNotifications() { return mPulsing; @@ -3050,7 +3053,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) - @Override public void cleanUpViewStateForEntry(NotificationEntry entry) { View child = entry.getRow(); if (child == mSwipeHelper.getTranslatingParentView()) { @@ -3317,7 +3319,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public void onViewAdded(View child) { super.onViewAdded(child); - onViewAddedInternal((ExpandableView) child); + if (child instanceof ExpandableView) { + onViewAddedInternal((ExpandableView) child); + } } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) @@ -3350,9 +3354,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.COORDINATOR) - private void onViewAddedInternal(ExpandableView child) { + void onViewAddedInternal(ExpandableView child) { + child.setOnHeightChangedListener(mOnChildHeightChangedListener); updateHideSensitiveForChild(child); - child.setOnHeightChangedListener(this); generateAddAnimation(child, false /* fromMoreCard */); updateAnimationState(child); updateChronometerForChild(child); @@ -3374,18 +3378,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd child.setHideSensitiveForIntrinsicHeight(mAmbientState.isHideSensitive()); } - @Override @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public void notifyGroupChildRemoved(ExpandableView row, ViewGroup childrenContainer) { onViewRemovedInternal(row, childrenContainer); } - @Override - @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void notifyGroupChildAdded(ExpandableView row) { - onViewAddedInternal(row); - } - @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) public void setAnimationsEnabled(boolean animationsEnabled) { mAnimationsEnabled = animationsEnabled; @@ -3410,33 +3407,29 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) - private void updateAnimationState(View child) { + void updateAnimationState(View child) { updateAnimationState((mAnimationsEnabled || hasPulsingNotifications()) && (mIsExpanded || isPinnedHeadsUp(child)), child); } - @Override @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void setExpandingNotification(ExpandableNotificationRow row) { + void setExpandingNotification(ExpandableNotificationRow row) { mAmbientState.setExpandingNotification(row); requestChildrenUpdate(); } - @Override @ShadeViewRefactor(RefactorComponent.ADAPTER) - public void bindRow(ExpandableNotificationRow row) { + void bindRow(ExpandableNotificationRow row) { row.setHeadsUpAnimatingAwayListener(animatingAway -> { mRoundnessManager.onHeadsupAnimatingAwayChanged(row, animatingAway); mHeadsUpAppearanceController.updateHeader(row.getEntry()); }); } - @Override public boolean containsView(View v) { return v.getParent() == this; } - @Override @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) public void applyExpandAnimationParams(ExpandAnimationParameters params) { mAmbientState.setExpandAnimationTopChange(params == null ? 0 : params.getTopChange()); @@ -3452,12 +3445,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) - public boolean isAddOrRemoveAnimationPending() { + boolean isAddOrRemoveAnimationPending() { return mNeedsAnimation && (!mChildrenToAddAnimated.isEmpty() || !mChildrenToRemoveAnimated.isEmpty()); } - @Override @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) public void generateAddAnimation(ExpandableView child, boolean fromMoreCard) { if (mIsExpanded && mAnimationsEnabled && !mChangePositionInProgress && !isFullyHidden()) { @@ -3475,7 +3467,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } } - @Override @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) public void changeViewPosition(ExpandableView child, int newIndex) { Assert.isMainThread(); @@ -4471,12 +4462,12 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.COORDINATOR) - public int getEmptyBottomMargin() { + int getEmptyBottomMargin() { return Math.max(mMaxLayoutHeight - mContentHeight, 0); } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void checkSnoozeLeavebehind() { + void checkSnoozeLeavebehind() { if (mCheckForLeavebehind) { mNotificationGutsManager.closeAndSaveGuts(true /* removeLeavebehind */, false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */, @@ -4486,19 +4477,19 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void resetCheckSnoozeLeavebehind() { + void resetCheckSnoozeLeavebehind() { mCheckForLeavebehind = true; } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) - public void onExpansionStarted() { + void onExpansionStarted() { mIsExpansionChanging = true; mAmbientState.setExpansionChanging(true); checkSnoozeLeavebehind(); } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) - public void onExpansionStopped() { + void onExpansionStopped() { mIsExpansionChanging = false; resetCheckSnoozeLeavebehind(); mAmbientState.setExpansionChanging(false); @@ -4547,20 +4538,20 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) - public void onPanelTrackingStarted() { + void onPanelTrackingStarted() { mPanelTracking = true; mAmbientState.setPanelTracking(true); resetExposedMenuView(true /* animate */, true /* force */); } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) - public void onPanelTrackingStopped() { + void onPanelTrackingStopped() { mPanelTracking = false; mAmbientState.setPanelTracking(false); } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) - public void resetScrollPosition() { + void resetScrollPosition() { mScroller.abortAnimation(); if (ANCHOR_SCROLLING) { // TODO: once we're recycling this will need to modify the adapter position instead @@ -4601,15 +4592,14 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.COORDINATOR) - private void updateChronometerForChild(View child) { + void updateChronometerForChild(View child) { if (child instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) child; row.setChronometerRunning(mIsExpanded); } } - @Override - public void onHeightChanged(ExpandableView view, boolean needsAnimation) { + void onChildHeightChanged(ExpandableView view, boolean needsAnimation) { updateContentHeight(); updateScrollPositionOnExpandInBottom(view); clampScrollPosition(); @@ -4632,8 +4622,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd requestChildrenUpdate(); } - @Override - public void onReset(ExpandableView view) { + void onChildHeightReset(ExpandableView view) { updateAnimationState(view); updateChronometerForChild(view); } @@ -4674,13 +4663,13 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void setOnHeightChangedListener( + void setOnHeightChangedListener( ExpandableView.OnHeightChangedListener onHeightChangedListener) { this.mOnHeightChangedListener = onHeightChangedListener; } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) - public void onChildAnimationFinished() { + void onChildAnimationFinished() { setAnimationRunning(false); requestChildrenUpdate(); runAnimationFinishedRunnables(); @@ -4724,7 +4713,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd * See {@link AmbientState#setDimmed}. */ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void setDimmed(boolean dimmed, boolean animate) { + void setDimmed(boolean dimmed, boolean animate) { dimmed &= onKeyguard(); mAmbientState.setDimmed(dimmed); if (animate && mAnimationsEnabled) { @@ -4789,7 +4778,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd * See {@link AmbientState#setActivatedChild}. */ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void setActivatedChild(ActivatableNotificationView activatedChild) { + void setActivatedChild(ActivatableNotificationView activatedChild) { mAmbientState.setActivatedChild(activatedChild); if (mAnimationsEnabled) { mActivateNeedsAnimation = true; @@ -4865,7 +4854,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd * @param lightTheme True if light theme should be used. */ @ShadeViewRefactor(RefactorComponent.DECORATOR) - public void updateDecorViews(boolean lightTheme) { + private void updateDecorViews(boolean lightTheme) { if (lightTheme == mUsingLightTheme) { return; } @@ -4880,7 +4869,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void goToFullShade(long delay) { + void goToFullShade(long delay) { mGoToFullShadeNeedsAnimation = true; mGoToFullShadeDelay = delay; mNeedsAnimation = true; @@ -4893,13 +4882,13 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.COORDINATOR) - public void setIntrinsicPadding(int intrinsicPadding) { + void setIntrinsicPadding(int intrinsicPadding) { mIntrinsicPadding = intrinsicPadding; mAmbientState.setIntrinsicPadding(intrinsicPadding); } @ShadeViewRefactor(RefactorComponent.COORDINATOR) - public int getIntrinsicPadding() { + int getIntrinsicPadding() { return mIntrinsicPadding; } @@ -4933,7 +4922,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd * animation curve. */ @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void setHideAmount(float linearHideAmount, float interpolatedHideAmount) { + void setHideAmount(float linearHideAmount, float interpolatedHideAmount) { mLinearHideAmount = linearHideAmount; mInterpolatedHideAmount = interpolatedHideAmount; boolean wasFullyHidden = mAmbientState.isFullyHidden(); @@ -4975,7 +4964,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) - public void notifyHideAnimationStart(boolean hide) { + void notifyHideAnimationStart(boolean hide) { // We only swap the scaling factor if we're fully hidden or fully awake to avoid // interpolation issues when playing with the power button. if (mInterpolatedHideAmount == 0 || mInterpolatedHideAmount == 1) { @@ -5003,7 +4992,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void setFooterView(@NonNull FooterView footerView) { + void setFooterView(@NonNull FooterView footerView) { int index = -1; if (mFooterView != null) { index = indexOfChild(mFooterView); @@ -5014,7 +5003,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void setEmptyShadeView(EmptyShadeView emptyShadeView) { + void setEmptyShadeView(EmptyShadeView emptyShadeView) { int index = -1; if (mEmptyShadeView != null) { index = indexOfChild(mEmptyShadeView); @@ -5025,7 +5014,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void updateEmptyShadeView(boolean visible) { + void updateEmptyShadeView(boolean visible) { mEmptyShadeView.setVisible(visible, mIsExpanded && mAnimationsEnabled); int oldTextRes = mEmptyShadeView.getTextResource(); @@ -5209,33 +5198,28 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } } - @Override @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public int getContainerChildCount() { return getChildCount(); } - @Override @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public View getContainerChildAt(int i) { return getChildAt(i); } - @Override @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public void removeContainerView(View v) { Assert.isMainThread(); removeView(v); } - @Override @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public void addContainerView(View v) { Assert.isMainThread(); addView(v); } - @Override public void addContainerViewAt(View v, int index) { Assert.isMainThread(); addView(v, index); @@ -5277,7 +5261,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd requestChildrenUpdate(); } - @Override public void setWillExpand(boolean willExpand) { mWillExpand = willExpand; } @@ -5742,7 +5725,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } } - @Override public void setNotificationActivityStarter( NotificationActivityStarter notificationActivityStarter) { mNotificationActivityStarter = notificationActivityStarter; @@ -5900,6 +5882,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd public void setController( NotificationStackScrollLayoutController notificationStackScrollLayoutController) { mController = notificationStackScrollLayoutController; + mController.getNoticationRoundessManager().setAnimatedChildren(mChildrenToAddAnimated); } public NotificationStackScrollLayoutController getController() { @@ -6000,7 +5983,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } } - @Override @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public void resetExposedMenuView(boolean animate, boolean force) { mSwipeHelper.resetExposedMenuView(animate, force); @@ -6752,7 +6734,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } changedRow.setChildrenExpanded(expanded, animated); if (!mGroupExpandedForMeasure) { - onHeightChanged(changedRow, false /* needsAnimation */); + onChildHeightChanged(changedRow, false /* needsAnimation */); } runAfterAnimationFinished(new Runnable() { @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index 8150593e69fd..53d3b7586f7e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -17,22 +17,29 @@ package com.android.systemui.statusbar.notification.stack; import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME; +import static com.android.systemui.statusbar.phone.NotificationIconAreaController.HIGH_PRIORITY; import android.graphics.PointF; +import android.provider.Settings; import android.view.Display; import android.view.View; import android.view.ViewGroup; import android.view.WindowInsets; import android.widget.FrameLayout; +import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper; import com.android.systemui.statusbar.NotificationShelfController; import com.android.systemui.statusbar.RemoteInputController; +import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; +import com.android.systemui.statusbar.notification.NotificationActivityStarter; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.phone.HeadsUpAppearanceController; +import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; import com.android.systemui.statusbar.phone.HeadsUpTouchHelper; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.NotificationIconAreaController; @@ -40,6 +47,7 @@ import com.android.systemui.statusbar.phone.NotificationPanelViewController; import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; +import com.android.systemui.tuner.TunerService; import java.util.function.BiConsumer; @@ -53,14 +61,25 @@ import javax.inject.Named; public class NotificationStackScrollLayoutController { private final boolean mAllowLongPress; private final NotificationGutsManager mNotificationGutsManager; + private final HeadsUpManagerPhone mHeadsUpManager; + private final NotificationRoundnessManager mNotificationRoundnessManager; + private final TunerService mTunerService; + private final NotificationListContainerImpl mNotificationListContainer = + new NotificationListContainerImpl(); private NotificationStackScrollLayout mView; @Inject public NotificationStackScrollLayoutController( @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress, - NotificationGutsManager notificationGutsManager) { + NotificationGutsManager notificationGutsManager, + HeadsUpManagerPhone headsUpManager, + NotificationRoundnessManager notificationRoundnessManager, + TunerService tunerService) { mAllowLongPress = allowLongPress; mNotificationGutsManager = notificationGutsManager; + mHeadsUpManager = headsUpManager; + mNotificationRoundnessManager = notificationRoundnessManager; + mTunerService = tunerService; } public void attach(NotificationStackScrollLayout view) { @@ -70,6 +89,17 @@ public class NotificationStackScrollLayoutController { if (mAllowLongPress) { mView.setLongPressListener(mNotificationGutsManager::openGuts); } + + mHeadsUpManager.addListener(mNotificationRoundnessManager); // TODO: why is this here? + + mNotificationRoundnessManager.setOnRoundingChangedCallback(mView::invalidate); + mView.addOnExpandedHeightChangedListener(mNotificationRoundnessManager::setExpanded); + + mTunerService.addTunable((key, newValue) -> { + if (key.equals(Settings.Secure.NOTIFICATION_DISMISS_RTL)) { + mView.updateDismissRtlSetting("1".equals(newValue)); + } + }, HIGH_PRIORITY, Settings.Secure.NOTIFICATION_DISMISS_RTL); } public void addOnExpandedHeightChangedListener(BiConsumer<Float, Float> listener) { @@ -457,10 +487,6 @@ public class NotificationStackScrollLayoutController { mView.onUpdateRowStates(); } - public boolean hasPulsingNotifications() { - return mView.hasPulsingNotifications(); - } - public ActivatableNotificationView getActivatedChild() { return mView.getActivatedChild(); } @@ -537,4 +563,151 @@ public class NotificationStackScrollLayoutController { public float calculateGapHeight(ExpandableView previousView, ExpandableView child, int count) { return mView.calculateGapHeight(previousView, child, count); } + + public NotificationRoundnessManager getNoticationRoundessManager() { + return mNotificationRoundnessManager; + } + + public NotificationListContainer getNotificationListContainer() { + return mNotificationListContainer; + } + + private class NotificationListContainerImpl implements NotificationListContainer { + @Override + public void setChildTransferInProgress(boolean childTransferInProgress) { + mView.setChildTransferInProgress(childTransferInProgress); + } + + @Override + public void changeViewPosition(ExpandableView child, int newIndex) { + mView.changeViewPosition(child, newIndex); + } + + @Override + public void notifyGroupChildAdded(ExpandableView row) { + mView.onViewAddedInternal(row); + } + + @Override + public void notifyGroupChildRemoved(ExpandableView row, ViewGroup childrenContainer) { + mView.notifyGroupChildRemoved(row, childrenContainer); + } + + @Override + public void generateAddAnimation(ExpandableView child, boolean fromMoreCard) { + mView.generateAddAnimation(child, fromMoreCard); + } + + @Override + public void generateChildOrderChangedEvent() { + mView.generateChildOrderChangedEvent(); + } + + @Override + public int getContainerChildCount() { + return mView.getContainerChildCount(); + } + + @Override + public void setNotificationActivityStarter( + NotificationActivityStarter notificationActivityStarter) { + mView.setNotificationActivityStarter(notificationActivityStarter); + } + + @Override + public View getContainerChildAt(int i) { + return mView.getContainerChildAt(i); + } + + @Override + public void removeContainerView(View v) { + mView.removeContainerView(v); + } + + @Override + public void addContainerView(View v) { + mView.addContainerView(v); + } + + @Override + public void addContainerViewAt(View v, int index) { + mView.addContainerViewAt(v, index); + } + + @Override + public void setMaxDisplayedNotifications(int maxNotifications) { + mView.setMaxDisplayedNotifications(maxNotifications); + } + + @Override + public ViewGroup getViewParentForNotification(NotificationEntry entry) { + return mView.getViewParentForNotification(entry); + } + + @Override + public void resetExposedMenuView(boolean animate, boolean force) { + mView.resetExposedMenuView(animate, force); + } + + @Override + public NotificationSwipeActionHelper getSwipeActionHelper() { + return mView.getSwipeActionHelper(); + } + + @Override + public void cleanUpViewStateForEntry(NotificationEntry entry) { + mView.cleanUpViewStateForEntry(entry); + } + + @Override + public void setChildLocationsChangedListener( + NotificationLogger.OnChildLocationsChangedListener listener) { + mView.setChildLocationsChangedListener(listener); + } + + public boolean hasPulsingNotifications() { + return mView.hasPulsingNotifications(); + } + + @Override + public boolean isInVisibleLocation(NotificationEntry entry) { + return mView.isInVisibleLocation(entry); + } + + @Override + public void onHeightChanged(ExpandableView view, boolean needsAnimation) { + mView.onChildHeightChanged(view, needsAnimation); + } + + @Override + public void onReset(ExpandableView view) { + mView.onChildHeightReset(view); + } + + @Override + public void bindRow(ExpandableNotificationRow row) { + mView.bindRow(row); + } + + @Override + public void applyExpandAnimationParams( + ActivityLaunchAnimator.ExpandAnimationParameters params) { + mView.applyExpandAnimationParams(params); + } + + @Override + public void setExpandingNotification(ExpandableNotificationRow row) { + mView.setExpandingNotification(row); + } + + @Override + public boolean containsView(View v) { + return mView.containsView(v); + } + + @Override + public void setWillExpand(boolean willExpand) { + mView.setWillExpand(willExpand); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AppButtonData.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AppButtonData.java deleted file mode 100644 index f6c1062f6749..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AppButtonData.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2015 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.statusbar.phone; - -import android.app.ActivityManager.RecentTaskInfo; - -import java.util.ArrayList; - -/** - * Data associated with an app button. - */ -class AppButtonData { - public final AppInfo appInfo; - public boolean pinned; - // Recent tasks for this app, sorted by lastActiveTime, descending. - public ArrayList<RecentTaskInfo> tasks; - - public AppButtonData(AppInfo appInfo, boolean pinned) { - this.appInfo = appInfo; - this.pinned = pinned; - } - - public int getTaskCount() { - return tasks == null ? 0 : tasks.size(); - } - - /** - * Returns true if the button contains no useful information and should be removed. - */ - public boolean isEmpty() { - return !pinned && getTaskCount() == 0; - } - - public void addTask(RecentTaskInfo task) { - if (tasks == null) { - tasks = new ArrayList<RecentTaskInfo>(); - } - tasks.add(task); - } - - public void clearTasks() { - if (tasks != null) { - tasks.clear(); - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AppInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AppInfo.java deleted file mode 100644 index 8f0b532eabee..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AppInfo.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2015 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.statusbar.phone; - -import android.content.ComponentName; -import android.os.UserHandle; - -/** - * Navigation bar app information. - */ -class AppInfo { - private final ComponentName mComponentName; - private final UserHandle mUser; - - public AppInfo(ComponentName componentName, UserHandle user) { - if (componentName == null || user == null) throw new IllegalArgumentException(); - mComponentName = componentName; - mUser = user; - } - - public ComponentName getComponentName() { - return mComponentName; - } - - public UserHandle getUser() { - return mUser; - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final AppInfo other = (AppInfo) obj; - return mComponentName.equals(other.mComponentName) && mUser.equals(other.mUser); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java index d6039af9232a..aeb2efd2026a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java @@ -138,7 +138,7 @@ public class AutoHideController { mHandler.postDelayed(mAutoHide, AUTO_HIDE_TIMEOUT_MS); } - void checkUserAutoHide(MotionEvent event) { + public void checkUserAutoHide(MotionEvent event) { boolean shouldHide = isAnyTransientBarShown() && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar. && event.getX() == 0 && event.getY() == 0; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java index 0731a568ae7d..31965d4fc4cd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java @@ -27,8 +27,8 @@ import android.view.ViewGroup; import android.widget.LinearLayout; import com.android.internal.statusbar.StatusBarIcon; -import com.android.systemui.DemoMode; import com.android.systemui.R; +import com.android.systemui.demomode.DemoMode; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver; import com.android.systemui.statusbar.StatusBarIconView; @@ -39,7 +39,9 @@ import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconStat import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState; import java.util.ArrayList; +import java.util.List; +//TODO: This should be a controller, not its own view public class DemoStatusIcons extends StatusIconContainer implements DemoMode, DarkReceiver { private static final String TAG = "DemoStatusIcons"; @@ -90,73 +92,84 @@ public class DemoStatusIcons extends StatusIconContainer implements DemoMode, Da } @Override + public List<String> demoCommands() { + List<String> commands = new ArrayList<>(); + commands.add(COMMAND_STATUS); + return commands; + } + + @Override + public void onDemoModeStarted() { + mDemoMode = true; + mStatusIcons.setVisibility(View.GONE); + setVisibility(View.VISIBLE); + } + + @Override + public void onDemoModeFinished() { + mDemoMode = false; + mStatusIcons.setVisibility(View.VISIBLE); + setVisibility(View.GONE); + } + + @Override public void dispatchDemoCommand(String command, Bundle args) { - if (!mDemoMode && command.equals(COMMAND_ENTER)) { - mDemoMode = true; - mStatusIcons.setVisibility(View.GONE); - setVisibility(View.VISIBLE); - } else if (mDemoMode && command.equals(COMMAND_EXIT)) { - mDemoMode = false; - mStatusIcons.setVisibility(View.VISIBLE); - setVisibility(View.GONE); - } else if (mDemoMode && command.equals(COMMAND_STATUS)) { - String volume = args.getString("volume"); - if (volume != null) { - int iconId = volume.equals("vibrate") ? R.drawable.stat_sys_ringer_vibrate - : 0; - updateSlot("volume", null, iconId); - } - String zen = args.getString("zen"); - if (zen != null) { - int iconId = zen.equals("dnd") ? R.drawable.stat_sys_dnd : 0; - updateSlot("zen", null, iconId); - } - String bt = args.getString("bluetooth"); - if (bt != null) { - int iconId = bt.equals("connected") - ? R.drawable.stat_sys_data_bluetooth_connected : 0; - updateSlot("bluetooth", null, iconId); - } - String location = args.getString("location"); - if (location != null) { - int iconId = location.equals("show") ? PhoneStatusBarPolicy.LOCATION_STATUS_ICON_ID - : 0; - updateSlot("location", null, iconId); - } - String alarm = args.getString("alarm"); - if (alarm != null) { - int iconId = alarm.equals("show") ? R.drawable.stat_sys_alarm - : 0; - updateSlot("alarm_clock", null, iconId); - } - String tty = args.getString("tty"); - if (tty != null) { - int iconId = tty.equals("show") ? R.drawable.stat_sys_tty_mode - : 0; - updateSlot("tty", null, iconId); - } - String mute = args.getString("mute"); - if (mute != null) { - int iconId = mute.equals("show") ? android.R.drawable.stat_notify_call_mute - : 0; - updateSlot("mute", null, iconId); - } - String speakerphone = args.getString("speakerphone"); - if (speakerphone != null) { - int iconId = speakerphone.equals("show") ? android.R.drawable.stat_sys_speakerphone - : 0; - updateSlot("speakerphone", null, iconId); - } - String cast = args.getString("cast"); - if (cast != null) { - int iconId = cast.equals("show") ? R.drawable.stat_sys_cast : 0; - updateSlot("cast", null, iconId); - } - String hotspot = args.getString("hotspot"); - if (hotspot != null) { - int iconId = hotspot.equals("show") ? R.drawable.stat_sys_hotspot : 0; - updateSlot("hotspot", null, iconId); - } + String volume = args.getString("volume"); + if (volume != null) { + int iconId = volume.equals("vibrate") ? R.drawable.stat_sys_ringer_vibrate + : 0; + updateSlot("volume", null, iconId); + } + String zen = args.getString("zen"); + if (zen != null) { + int iconId = zen.equals("dnd") ? R.drawable.stat_sys_dnd : 0; + updateSlot("zen", null, iconId); + } + String bt = args.getString("bluetooth"); + if (bt != null) { + int iconId = bt.equals("connected") + ? R.drawable.stat_sys_data_bluetooth_connected : 0; + updateSlot("bluetooth", null, iconId); + } + String location = args.getString("location"); + if (location != null) { + int iconId = location.equals("show") ? PhoneStatusBarPolicy.LOCATION_STATUS_ICON_ID + : 0; + updateSlot("location", null, iconId); + } + String alarm = args.getString("alarm"); + if (alarm != null) { + int iconId = alarm.equals("show") ? R.drawable.stat_sys_alarm + : 0; + updateSlot("alarm_clock", null, iconId); + } + String tty = args.getString("tty"); + if (tty != null) { + int iconId = tty.equals("show") ? R.drawable.stat_sys_tty_mode + : 0; + updateSlot("tty", null, iconId); + } + String mute = args.getString("mute"); + if (mute != null) { + int iconId = mute.equals("show") ? android.R.drawable.stat_notify_call_mute + : 0; + updateSlot("mute", null, iconId); + } + String speakerphone = args.getString("speakerphone"); + if (speakerphone != null) { + int iconId = speakerphone.equals("show") ? android.R.drawable.stat_sys_speakerphone + : 0; + updateSlot("speakerphone", null, iconId); + } + String cast = args.getString("cast"); + if (cast != null) { + int iconId = cast.equals("show") ? R.drawable.stat_sys_cast : 0; + updateSlot("cast", null, iconId); + } + String hotspot = args.getString("hotspot"); + if (hotspot != null) { + int iconId = hotspot.equals("show") ? R.drawable.stat_sys_hotspot : 0; + updateSlot("hotspot", null, iconId); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java index 3e5eb5fba8f2..982773aa9d86 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java @@ -32,6 +32,7 @@ import com.android.internal.colorextraction.ColorExtractor.GradientColors; import com.android.internal.view.AppearanceRegion; import com.android.systemui.Dumpable; import com.android.systemui.R; +import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.statusbar.policy.BatteryController; @@ -125,7 +126,7 @@ public class LightBarController implements BatteryController.BatteryStateChangeC updateStatus(); } - void onNavigationBarAppearanceChanged(@Appearance int appearance, boolean nbModeChanged, + public void onNavigationBarAppearanceChanged(@Appearance int appearance, boolean nbModeChanged, int navigationBarMode, boolean navbarColorManagedByIme) { int diff = appearance ^ mAppearance; if ((diff & APPEARANCE_LIGHT_NAVIGATION_BARS) != 0 || nbModeChanged) { @@ -144,7 +145,7 @@ public class LightBarController implements BatteryController.BatteryStateChangeC mNavbarColorManagedByIme = navbarColorManagedByIme; } - void onNavigationBarModeChanged(int newBarMode) { + public void onNavigationBarModeChanged(int newBarMode) { mHasLightNavigationBar = isLight(mAppearance, newBarMode, APPEARANCE_LIGHT_NAVIGATION_BARS); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java index 07e9f944b802..8e9dcb4375d5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java @@ -24,6 +24,8 @@ import android.content.pm.UserInfo; import android.os.UserHandle; import android.os.UserManager; +import androidx.annotation.NonNull; + import com.android.systemui.broadcast.BroadcastDispatcher; import java.util.ArrayList; @@ -57,7 +59,8 @@ public class ManagedProfileControllerImpl implements ManagedProfileController { mProfiles = new LinkedList<UserInfo>(); } - public void addCallback(Callback callback) { + @Override + public void addCallback(@NonNull Callback callback) { mCallbacks.add(callback); if (mCallbacks.size() == 1) { setListening(true); @@ -65,7 +68,8 @@ public class ManagedProfileControllerImpl implements ManagedProfileController { callback.onManagedProfileChanged(); } - public void removeCallback(Callback callback) { + @Override + public void removeCallback(@NonNull Callback callback) { if (mCallbacks.remove(callback) && mCallbacks.size() == 0) { setListening(false); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java index 7bbe1c986249..0e413fba0ad5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java @@ -5,6 +5,7 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Color; import android.graphics.Rect; +import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -20,6 +21,8 @@ import com.android.settingslib.Utils; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.demomode.DemoMode; +import com.android.systemui.demomode.DemoModeController; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -35,6 +38,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import java.util.ArrayList; +import java.util.List; import java.util.Objects; import java.util.function.Function; @@ -44,7 +48,8 @@ import java.util.function.Function; */ public class NotificationIconAreaController implements DarkReceiver, StatusBarStateController.StateListener, - NotificationWakeUpCoordinator.WakeUpListener { + NotificationWakeUpCoordinator.WakeUpListener, + DemoMode { public static final String HIGH_PRIORITY = "high_priority"; private static final long AOD_ICONS_APPEAR_DURATION = 200; @@ -74,6 +79,8 @@ public class NotificationIconAreaController implements DarkReceiver, private final Rect mTintArea = new Rect(); private ViewGroup mNotificationScrollLayout; private Context mContext; + private final DemoModeController mDemoModeController; + private int mAodIconAppearTranslation; private boolean mAnimationsEnabled; @@ -104,7 +111,8 @@ public class NotificationIconAreaController implements DarkReceiver, NotificationMediaManager notificationMediaManager, NotificationListener notificationListener, DozeParameters dozeParameters, - BubbleController bubbleController) { + BubbleController bubbleController, + DemoModeController demoModeController) { mStatusBar = statusBar; mContrastColorUtil = ContrastColorUtil.getInstance(context); mContext = context; @@ -117,6 +125,8 @@ public class NotificationIconAreaController implements DarkReceiver, mBypassController = keyguardBypassController; mBubbleController = bubbleController; notificationListener.addNotificationSettingsListener(mSettingsListener); + mDemoModeController = demoModeController; + mDemoModeController.addCallback(this); initializeNotificationAreaViews(context); reloadAodColor(); @@ -666,4 +676,27 @@ public class NotificationIconAreaController implements DarkReceiver, } } } + + @Override + public List<String> demoCommands() { + ArrayList<String> commands = new ArrayList<>(); + commands.add(DemoMode.COMMAND_NOTIFICATIONS); + return commands; + } + + @Override + public void dispatchDemoCommand(String command, Bundle args) { + if (mNotificationIconArea != null) { + String visible = args.getString("visible"); + int vis = "false".equals(visible) ? View.INVISIBLE : View.VISIBLE; + mNotificationIconArea.setVisibility(vis); + } + } + + @Override + public void onDemoModeFinished() { + if (mNotificationIconArea != null) { + mNotificationIconArea.setVisibility(View.VISIBLE); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index 70fb71a1d2f2..42fbe5967d42 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -3074,7 +3074,8 @@ public class NotificationPanelViewController extends PanelViewController { } public boolean hasPulsingNotifications() { - return mNotificationStackScrollLayoutController.hasPulsingNotifications(); + return mNotificationStackScrollLayoutController + .getNotificationListContainer().hasPulsingNotifications(); } public ActivatableNotificationView getActivatedChild() { @@ -3259,6 +3260,10 @@ public class NotificationPanelViewController extends PanelViewController { return new OnConfigurationChangedListener(); } + public NotificationStackScrollLayoutController getNotificationStackScrollLayoutController() { + return mNotificationStackScrollLayoutController; + } + private class OnHeightChangedListener implements ExpandableView.OnHeightChangedListener { @Override public void onHeightChanged(ExpandableView view, boolean needsAnimation) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 6cd33c6872c7..4fbd49a6fe4f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -138,7 +138,6 @@ import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.ActivityIntentHelper; import com.android.systemui.AutoReinflateContainer; import com.android.systemui.DejankUtils; -import com.android.systemui.DemoMode; import com.android.systemui.Dumpable; import com.android.systemui.EventLogTags; import com.android.systemui.InitController; @@ -153,12 +152,17 @@ import com.android.systemui.charging.WirelessChargingAnimation; import com.android.systemui.classifier.FalsingLog; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.dagger.qualifiers.UiBackground; +import com.android.systemui.demomode.DemoMode; +import com.android.systemui.demomode.DemoModeCommandReceiver; +import com.android.systemui.demomode.DemoModeController; import com.android.systemui.fragments.ExtensionFragmentListener; import com.android.systemui.fragments.FragmentHostManager; import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.keyguard.WakefulnessLifecycle; +import com.android.systemui.navigationbar.NavigationBarController; +import com.android.systemui.navigationbar.NavigationBarView; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.FalsingManager; @@ -182,7 +186,6 @@ import com.android.systemui.statusbar.CrossFadeHelper; import com.android.systemui.statusbar.GestureRecorder; import com.android.systemui.statusbar.KeyboardShortcuts; import com.android.systemui.statusbar.KeyguardIndicationController; -import com.android.systemui.statusbar.NavigationBarController; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.NotificationPresenter; @@ -210,6 +213,7 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; import com.android.systemui.statusbar.phone.dagger.StatusBarPhoneModule; import com.android.systemui.statusbar.policy.BatteryController; @@ -231,6 +235,8 @@ import com.android.systemui.volume.VolumeComponent; import java.io.FileDescriptor; import java.io.PrintWriter; import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.Executor; @@ -395,6 +401,7 @@ public class StatusBar extends SystemUI implements DemoMode, private final ExtensionController mExtensionController; private final UserInfoControllerImpl mUserInfoControllerImpl; private final DismissCallbackRegistry mDismissCallbackRegistry; + private final DemoModeController mDemoModeController; private NotificationsController mNotificationsController; // expanded notifications @@ -646,6 +653,7 @@ public class StatusBar extends SystemUI implements DemoMode, private final BubbleController.BubbleExpandListener mBubbleExpandListener; private ActivityIntentHelper mActivityIntentHelper; + private NotificationStackScrollLayoutController mStackScrollerController; /** * Public constructor for StatusBar. @@ -731,6 +739,7 @@ public class StatusBar extends SystemUI implements DemoMode, PhoneStatusBarPolicy phoneStatusBarPolicy, KeyguardIndicationController keyguardIndicationController, DismissCallbackRegistry dismissCallbackRegistry, + DemoModeController demoModeController, Lazy<NotificationShadeDepthController> notificationShadeDepthControllerLazy, StatusBarTouchableRegionManager statusBarTouchableRegionManager) { super(context); @@ -809,6 +818,7 @@ public class StatusBar extends SystemUI implements DemoMode, mUserInfoControllerImpl = userInfoControllerImpl; mIconPolicy = phoneStatusBarPolicy; mDismissCallbackRegistry = dismissCallbackRegistry; + mDemoModeController = demoModeController; mBubbleExpandListener = (isExpanding, key) -> { @@ -863,6 +873,9 @@ public class StatusBar extends SystemUI implements DemoMode, // Connect in to the status bar manager service mCommandQueue.addCallback(this); + // Listen for demo mode changes + mDemoModeController.addCallback(this); + RegisterStatusBarResult result = null; try { result = mBarService.registerStatusBar(mCommandQueue); @@ -1016,9 +1029,11 @@ public class StatusBar extends SystemUI implements DemoMode, // TODO: Deal with the ugliness that comes from having some of the statusbar broken out // into fragments, but the rest here, it leaves some awkward lifecycle and whatnot. - mStackScroller = mNotificationShadeWindowView.findViewById( - R.id.notification_stack_scroller); - NotificationListContainer notifListContainer = (NotificationListContainer) mStackScroller; + mStackScrollerController = + mNotificationPanelViewController.getNotificationStackScrollLayoutController(); + mStackScroller = mStackScrollerController.getView(); + NotificationListContainer notifListContainer = + mStackScrollerController.getNotificationListContainer(); mNotificationLogger.setUpWithContainer(notifListContainer); // TODO: make this injectable. Currently that would create a circular dependency between @@ -1026,7 +1041,7 @@ public class StatusBar extends SystemUI implements DemoMode, mNotificationIconAreaController = SystemUIFactory.getInstance() .createNotificationIconAreaController(context, this, mWakeUpCoordinator, mKeyguardBypassController, - mStatusBarStateController); + mStatusBarStateController, mDemoModeController); mWakeUpCoordinator.setIconAreaController(mNotificationIconAreaController); inflateShelf(); mNotificationIconAreaController.setupShelf(mNotificationShelfController); @@ -1249,7 +1264,6 @@ public class StatusBar extends SystemUI implements DemoMode, if (DEBUG_MEDIA_FAKE_ARTWORK) { demoFilter.addAction(ACTION_FAKE_ARTWORK); } - demoFilter.addAction(ACTION_DEMO); context.registerReceiverAsUser(mDemoReceiver, UserHandle.ALL, demoFilter, android.Manifest.permission.DUMP, null); @@ -1301,13 +1315,15 @@ public class StatusBar extends SystemUI implements DemoMode, mActivityLaunchAnimator = new ActivityLaunchAnimator( mNotificationShadeWindowViewController, this, mNotificationPanelViewController, mNotificationShadeDepthControllerLazy.get(), - (NotificationListContainer) mStackScroller, mContext.getMainExecutor()); + mStackScrollerController.getNotificationListContainer(), + mContext.getMainExecutor()); // TODO: inject this. mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanelViewController, - mHeadsUpManager, mNotificationShadeWindowView, mStackScroller, mDozeScrimController, - mScrimController, mActivityLaunchAnimator, mDynamicPrivacyController, - mKeyguardStateController, mKeyguardIndicationController, + mHeadsUpManager, mNotificationShadeWindowView, mStackScrollerController, + mDozeScrimController, mScrimController, mActivityLaunchAnimator, + mDynamicPrivacyController, mKeyguardStateController, + mKeyguardIndicationController, this /* statusBar */, mShadeController, mCommandQueue, mInitController, mNotificationInterruptStateProvider); @@ -1321,16 +1337,13 @@ public class StatusBar extends SystemUI implements DemoMode, .setNotificationPresenter(mPresenter) .setNotificationPanelViewController(mNotificationPanelViewController) .build(); - - ((NotificationListContainer) mStackScroller) - .setNotificationActivityStarter(mNotificationActivityStarter); - + mStackScroller.setNotificationActivityStarter(mNotificationActivityStarter); mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter); mNotificationsController.initialize( this, mPresenter, - (NotificationListContainer) mStackScroller, + mStackScrollerController.getNotificationListContainer(), mNotificationActivityStarter, mPresenter); } @@ -1502,7 +1515,7 @@ public class StatusBar extends SystemUI implements DemoMode, return mStatusBarWindowController.getStatusBarHeight(); } - protected boolean toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction) { + public boolean toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction) { if (!mRecentsOptional.isPresent()) { return false; } @@ -2435,8 +2448,8 @@ public class StatusBar extends SystemUI implements DemoMode, return mNotificationShadeWindowViewController.getBarTransitions(); } - void checkBarModes() { - if (mDemoMode) return; + public void checkBarModes() { + if (mDemoModeController.isInDemoMode()) return; if (mNotificationShadeWindowViewController != null && getStatusBarTransitions() != null) { checkBarMode(mStatusBarMode, mStatusBarWindowState, getStatusBarTransitions()); } @@ -2445,7 +2458,7 @@ public class StatusBar extends SystemUI implements DemoMode, } // Called by NavigationBarFragment - void setQsScrimEnabled(boolean scrimEnabled) { + public void setQsScrimEnabled(boolean scrimEnabled) { mNotificationPanelViewController.setQsScrimEnabled(scrimEnabled); } @@ -2618,7 +2631,7 @@ public class StatusBar extends SystemUI implements DemoMode, } } - static void dumpBarTransitions(PrintWriter pw, String var, BarTransitions transitions) { + public static void dumpBarTransitions(PrintWriter pw, String var, BarTransitions transitions) { pw.print(" "); pw.print(var); pw.print(".BarTransitions.mMode="); pw.println(BarTransitions.modeToString(transitions.getMode())); } @@ -2809,19 +2822,7 @@ public class StatusBar extends SystemUI implements DemoMode, public void onReceive(Context context, Intent intent) { if (DEBUG) Log.v(TAG, "onReceive: " + intent); String action = intent.getAction(); - if (ACTION_DEMO.equals(action)) { - Bundle bundle = intent.getExtras(); - if (bundle != null) { - String command = bundle.getString("command", "").trim().toLowerCase(); - if (command.length() > 0) { - try { - dispatchDemoCommand(command, bundle); - } catch (Throwable t) { - Log.w(TAG, "Error running demo command, intent=" + intent, t); - } - } - } - } else if (ACTION_FAKE_ARTWORK.equals(action)) { + if (ACTION_FAKE_ARTWORK.equals(action)) { if (DEBUG_MEDIA_FAKE_ARTWORK) { mPresenter.updateMediaMetaData(true, true); } @@ -3085,50 +3086,34 @@ public class StatusBar extends SystemUI implements DemoMode, startActivityDismissingKeyguard(intent, onlyProvisioned, true /* dismissShade */); } - private boolean mDemoModeAllowed; - private boolean mDemoMode; + @Override + public List<String> demoCommands() { + List<String> s = new ArrayList<>(); + s.add(DemoMode.COMMAND_BARS); + s.add(DemoMode.COMMAND_CLOCK); + s.add(DemoMode.COMMAND_OPERATOR); + return s; + } @Override - public void dispatchDemoCommand(String command, Bundle args) { - if (!mDemoModeAllowed) { - mDemoModeAllowed = Settings.Global.getInt(mContext.getContentResolver(), - DEMO_MODE_ALLOWED, 0) != 0; - } - if (!mDemoModeAllowed) return; - if (command.equals(COMMAND_ENTER)) { - mDemoMode = true; - } else if (command.equals(COMMAND_EXIT)) { - mDemoMode = false; - checkBarModes(); - } else if (!mDemoMode) { - // automatically enter demo mode on first demo command - dispatchDemoCommand(COMMAND_ENTER, new Bundle()); - } - boolean modeChange = command.equals(COMMAND_ENTER) || command.equals(COMMAND_EXIT); - if ((modeChange || command.equals(COMMAND_VOLUME)) && mVolumeComponent != null) { - mVolumeComponent.dispatchDemoCommand(command, args); - } - if (modeChange || command.equals(COMMAND_CLOCK)) { + public void onDemoModeStarted() { + // Must send this message to any view that we delegate to via dispatchDemoCommandToView + dispatchDemoModeStartedToView(R.id.clock); + dispatchDemoModeStartedToView(R.id.operator_name); + } + + @Override + public void onDemoModeFinished() { + dispatchDemoModeFinishedToView(R.id.clock); + dispatchDemoModeFinishedToView(R.id.operator_name); + checkBarModes(); + } + + @Override + public void dispatchDemoCommand(String command, @NonNull Bundle args) { + if (command.equals(COMMAND_CLOCK)) { dispatchDemoCommandToView(command, args, R.id.clock); } - if (modeChange || command.equals(COMMAND_BATTERY)) { - mBatteryController.dispatchDemoCommand(command, args); - } - if (modeChange || command.equals(COMMAND_STATUS)) { - ((StatusBarIconControllerImpl) mIconController).dispatchDemoCommand(command, args); - } - if (mNetworkController != null && (modeChange || command.equals(COMMAND_NETWORK))) { - mNetworkController.dispatchDemoCommand(command, args); - } - if (modeChange || command.equals(COMMAND_NOTIFICATIONS)) { - View notifications = mStatusBarView == null ? null - : mStatusBarView.findViewById(R.id.notification_icon_area); - if (notifications != null) { - String visible = args.getString("visible"); - int vis = mDemoMode && "false".equals(visible) ? View.INVISIBLE : View.VISIBLE; - notifications.setVisibility(vis); - } - } if (command.equals(COMMAND_BARS)) { String mode = args.getString("mode"); int barMode = "opaque".equals(mode) ? MODE_OPAQUE : @@ -3147,16 +3132,33 @@ public class StatusBar extends SystemUI implements DemoMode, mNavigationBarController.transitionTo(mDisplayId, barMode, animate); } } - if (modeChange || command.equals(COMMAND_OPERATOR)) { + if (command.equals(COMMAND_OPERATOR)) { dispatchDemoCommandToView(command, args, R.id.operator_name); } } + //TODO: these should have controllers, and this method should be removed private void dispatchDemoCommandToView(String command, Bundle args, int id) { if (mStatusBarView == null) return; View v = mStatusBarView.findViewById(id); - if (v instanceof DemoMode) { - ((DemoMode)v).dispatchDemoCommand(command, args); + if (v instanceof DemoModeCommandReceiver) { + ((DemoModeCommandReceiver) v).dispatchDemoCommand(command, args); + } + } + + private void dispatchDemoModeStartedToView(int id) { + if (mStatusBarView == null) return; + View v = mStatusBarView.findViewById(id); + if (v instanceof DemoModeCommandReceiver) { + ((DemoModeCommandReceiver) v).onDemoModeStarted(); + } + } + + private void dispatchDemoModeFinishedToView(int id) { + if (mStatusBarView == null) return; + View v = mStatusBarView.findViewById(id); + if (v instanceof DemoModeCommandReceiver) { + ((DemoModeCommandReceiver) v).onDemoModeFinished(); } } @@ -4132,7 +4134,7 @@ public class StatusBar extends SystemUI implements DemoMode, toggleSplitScreenMode(-1 /* metricsDockAction */, -1 /* metricsUndockAction */); } - void awakenDreams() { + public void awakenDreams() { mUiBgExecutor.execute(() -> { try { mDreamManager.awaken(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java index 8ff7a41cb22f..f0efed332c7f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java @@ -32,9 +32,9 @@ import android.widget.LinearLayout.LayoutParams; import androidx.annotation.VisibleForTesting; import com.android.internal.statusbar.StatusBarIcon; -import com.android.systemui.DemoMode; import com.android.systemui.Dependency; import com.android.systemui.R; +import com.android.systemui.demomode.DemoModeCommandReceiver; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver; import com.android.systemui.statusbar.CommandQueue; @@ -198,7 +198,7 @@ public interface StatusBarIconController { /** * Turns info from StatusBarIconController into ImageViews in a ViewGroup. */ - public static class IconManager implements DemoMode { + class IconManager implements DemoModeCommandReceiver { protected final ViewGroup mGroup; protected final Context mContext; protected final int mIconSize; @@ -390,18 +390,24 @@ public interface StatusBarIconController { return; } - if (command.equals(COMMAND_EXIT)) { - if (mDemoStatusIcons != null) { - mDemoStatusIcons.dispatchDemoCommand(command, args); - exitDemoMode(); - } + mDemoStatusIcons.dispatchDemoCommand(command, args); + } + + @Override + public void onDemoModeStarted() { + mIsInDemoMode = true; + if (mDemoStatusIcons == null) { + mDemoStatusIcons = createDemoStatusIcons(); + } + mDemoStatusIcons.onDemoModeStarted(); + } + + @Override + public void onDemoModeFinished() { + if (mDemoStatusIcons != null) { + mDemoStatusIcons.onDemoModeFinished(); + exitDemoMode(); mIsInDemoMode = false; - } else { - if (mDemoStatusIcons == null) { - mIsInDemoMode = true; - mDemoStatusIcons = createDemoStatusIcons(); - } - mDemoStatusIcons.dispatchDemoCommand(command, args); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java index 21e1d319cffa..60ef52351393 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java @@ -29,6 +29,8 @@ import com.android.internal.statusbar.StatusBarIcon; import com.android.systemui.Dependency; import com.android.systemui.Dumpable; import com.android.systemui.R; +import com.android.systemui.demomode.DemoMode; +import com.android.systemui.demomode.DemoModeController; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.StatusIconDisplayable; import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState; @@ -54,22 +56,20 @@ import javax.inject.Singleton; */ @Singleton public class StatusBarIconControllerImpl extends StatusBarIconList implements Tunable, - ConfigurationListener, Dumpable, CommandQueue.Callbacks, StatusBarIconController { + ConfigurationListener, Dumpable, CommandQueue.Callbacks, StatusBarIconController, DemoMode { private static final String TAG = "StatusBarIconController"; private final ArrayList<IconManager> mIconGroups = new ArrayList<>(); private final ArraySet<String> mIconHideList = new ArraySet<>(); - // Points to light or dark context depending on the... context? private Context mContext; - private Context mLightContext; - private Context mDarkContext; - - private boolean mIsDark = false; @Inject - public StatusBarIconControllerImpl(Context context, CommandQueue commandQueue) { + public StatusBarIconControllerImpl( + Context context, + CommandQueue commandQueue, + DemoModeController demoModeController) { super(context.getResources().getStringArray( com.android.internal.R.array.config_statusBarIcons)); Dependency.get(ConfigurationController.class).addCallback(this); @@ -80,6 +80,7 @@ public class StatusBarIconControllerImpl extends StatusBarIconList implements Tu commandQueue.addCallback(this); Dependency.get(TunerService.class).addTunable(this, ICON_HIDE_LIST); + demoModeController.addCallback(this); } @Override @@ -339,6 +340,25 @@ public class StatusBarIconControllerImpl extends StatusBarIconList implements Tu super.dump(pw); } + @Override + public void onDemoModeStarted() { + for (IconManager manager : mIconGroups) { + if (manager.isDemoable()) { + manager.onDemoModeStarted(); + } + } + } + + @Override + public void onDemoModeFinished() { + for (IconManager manager : mIconGroups) { + if (manager.isDemoable()) { + manager.onDemoModeFinished(); + } + } + } + + @Override public void dispatchDemoCommand(String command, Bundle args) { for (IconManager manager : mIconGroups) { if (manager.isDemoable()) { @@ -348,6 +368,13 @@ public class StatusBarIconControllerImpl extends StatusBarIconList implements Tu } @Override + public List<String> demoCommands() { + List<String> s = new ArrayList<>(); + s.add(DemoMode.COMMAND_STATUS); + return s; + } + + @Override public void onDensityOrFontScaleChanged() { loadDimens(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 81d0699a29e6..f3a7c501f6e8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -49,6 +49,7 @@ import com.android.systemui.DejankUtils; import com.android.systemui.SystemUIFactory; import com.android.systemui.dock.DockManager; import com.android.systemui.keyguard.DismissCallbackRegistry; +import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.shared.system.QuickStepContract; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java index 4de648402464..b9f94b37d7d3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -49,7 +49,6 @@ import com.android.systemui.ActivityIntentHelper; import com.android.systemui.EventLogTags; import com.android.systemui.assist.AssistManager; import com.android.systemui.bubbles.BubbleController; -import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.plugins.ActivityStarter; @@ -93,7 +92,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit private final CommandQueue mCommandQueue; private final Handler mMainThreadHandler; - private final Handler mBackgroundHandler; private final Executor mUiBgExecutor; private final NotificationEntryManager mEntryManager; @@ -134,7 +132,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit Context context, CommandQueue commandQueue, Handler mainThreadHandler, - Handler backgroundHandler, Executor uiBgExecutor, NotificationEntryManager entryManager, NotifPipeline notifPipeline, @@ -170,7 +167,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mContext = context; mCommandQueue = commandQueue; mMainThreadHandler = mainThreadHandler; - mBackgroundHandler = backgroundHandler; mUiBgExecutor = uiBgExecutor; mEntryManager = entryManager; mNotifPipeline = notifPipeline; @@ -307,7 +303,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable); mShadeController.collapsePanel(); } else { - mBackgroundHandler.postAtFrontOfQueue(runnable); + runnable.run(); } return !mNotificationPanel.isFullyCollapsed(); } @@ -605,7 +601,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit private final Context mContext; private final CommandQueue mCommandQueue; private final Handler mMainThreadHandler; - private final Handler mBackgroundHandler; + private final Executor mUiBgExecutor; private final NotificationEntryManager mEntryManager; private final NotifPipeline mNotifPipeline; @@ -644,7 +640,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit Context context, CommandQueue commandQueue, @Main Handler mainThreadHandler, - @Background Handler backgroundHandler, @UiBackground Executor uiBgExecutor, NotificationEntryManager entryManager, NotifPipeline notifPipeline, @@ -676,7 +671,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mContext = context; mCommandQueue = commandQueue; mMainThreadHandler = mainThreadHandler; - mBackgroundHandler = backgroundHandler; mUiBgExecutor = uiBgExecutor; mEntryManager = entryManager; mNotifPipeline = notifPipeline; @@ -734,7 +728,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mContext, mCommandQueue, mMainThreadHandler, - mBackgroundHandler, mUiBgExecutor, mEntryManager, mNotifPipeline, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java index 45f0c49a4fd4..f1715bef62d2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java @@ -30,7 +30,6 @@ import android.service.vr.IVrStateCallbacks; import android.util.Log; import android.util.Slog; import android.view.View; -import android.view.ViewGroup; import android.view.accessibility.AccessibilityManager; import android.widget.TextView; @@ -71,7 +70,7 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener; import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener; -import com.android.systemui.statusbar.notification.stack.NotificationListContainer; +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -133,7 +132,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, NotificationPanelViewController panel, HeadsUpManagerPhone headsUp, NotificationShadeWindowView statusBarWindow, - ViewGroup stackScroller, + NotificationStackScrollLayoutController stackScrollerController, DozeScrimController dozeScrimController, ScrimController scrimController, ActivityLaunchAnimator activityLaunchAnimator, @@ -155,7 +154,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, mStatusBar = statusBar; mShadeController = shadeController; mCommandQueue = commandQueue; - mAboveShelfObserver = new AboveShelfObserver(stackScroller); + mAboveShelfObserver = new AboveShelfObserver(stackScrollerController.getView()); mActivityLaunchAnimator = activityLaunchAnimator; mAboveShelfObserver.setListener(statusBarWindow.findViewById( R.id.notification_container_parent)); @@ -190,7 +189,6 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, remoteInputManager.getController().addCallback( Dependency.get(NotificationShadeWindowController.class)); - NotificationListContainer notifListContainer = (NotificationListContainer) stackScroller; initController.addPostInitTask(() -> { NotificationEntryListener notificationEntryListener = new NotificationEntryListener() { @Override @@ -207,7 +205,8 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, } }; - mViewHierarchyManager.setUpWithPresenter(this, notifListContainer); + mViewHierarchyManager.setUpWithPresenter(this, + stackScrollerController.getNotificationListContainer()); mEntryManager.setUpWithPresenter(this); mEntryManager.addNotificationEntryListener(notificationEntryListener); mEntryManager.addNotificationLifetimeExtender(mHeadsUpManager); @@ -219,7 +218,8 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, mMediaManager.setUpWithPresenter(this); mVisualStabilityManager.setUpWithPresenter(this); mGutsManager.setUpWithPresenter(this, - notifListContainer, mCheckSaveListener, mOnSettingsClickListener); + stackScrollerController.getNotificationListContainer(), mCheckSaveListener, + mOnSettingsClickListener); // ForegroundServiceNotificationListener adds its listener in its constructor // but we need to request it here in order for it to be instantiated. // TODO: figure out how to do this correctly once Dependency.get() is gone. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java index 02e031217904..dd4af540b2f5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java @@ -34,10 +34,12 @@ import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.bubbles.BubbleController; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.dagger.qualifiers.UiBackground; +import com.android.systemui.demomode.DemoModeController; import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.keyguard.WakefulnessLifecycle; +import com.android.systemui.navigationbar.NavigationBarController; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.PluginDependencyProvider; @@ -47,7 +49,6 @@ import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.stackdivider.Divider; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.KeyguardIndicationController; -import com.android.systemui.statusbar.NavigationBarController; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.NotificationRemoteInputManager; @@ -196,6 +197,7 @@ public interface StatusBarPhoneModule { UserInfoControllerImpl userInfoControllerImpl, PhoneStatusBarPolicy phoneStatusBarPolicy, KeyguardIndicationController keyguardIndicationController, + DemoModeController demoModeController, Lazy<NotificationShadeDepthController> notificationShadeDepthController, DismissCallbackRegistry dismissCallbackRegistry, StatusBarTouchableRegionManager statusBarTouchableRegionManager) { @@ -275,6 +277,7 @@ public interface StatusBarPhoneModule { phoneStatusBarPolicy, keyguardIndicationController, dismissCallbackRegistry, + demoModeController, notificationShadeDepthController, statusBarTouchableRegionManager); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityManagerWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityManagerWrapper.java index 1395e1377529..c0caabd7501a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityManagerWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityManagerWrapper.java @@ -19,6 +19,8 @@ import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener; +import androidx.annotation.NonNull; + import javax.inject.Inject; import javax.inject.Singleton; @@ -37,12 +39,12 @@ public class AccessibilityManagerWrapper implements } @Override - public void addCallback(AccessibilityServicesStateChangeListener listener) { + public void addCallback(@NonNull AccessibilityServicesStateChangeListener listener) { mAccessibilityManager.addAccessibilityServicesStateChangeListener(listener, null); } @Override - public void removeCallback(AccessibilityServicesStateChangeListener listener) { + public void removeCallback(@NonNull AccessibilityServicesStateChangeListener listener) { mAccessibilityManager.removeAccessibilityServicesStateChangeListener(listener); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java index e5a46797d035..06e4731265e3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java @@ -18,8 +18,8 @@ package com.android.systemui.statusbar.policy; import android.annotation.Nullable; -import com.android.systemui.DemoMode; import com.android.systemui.Dumpable; +import com.android.systemui.demomode.DemoMode; import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback; import java.io.FileDescriptor; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java index 88a6263c1dca..b7dc821e4a8c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java @@ -27,6 +27,7 @@ import android.os.PowerManager; import android.os.PowerSaveState; import android.util.Log; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; @@ -36,11 +37,14 @@ import com.android.settingslib.utils.PowerUtil; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.demomode.DemoMode; +import com.android.systemui.demomode.DemoModeController; import com.android.systemui.power.EnhancedEstimates; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; @@ -63,6 +67,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC mChangeCallbacks = new ArrayList<>(); private final ArrayList<EstimateFetchCompletion> mFetchCallbacks = new ArrayList<>(); private final PowerManager mPowerManager; + private final DemoModeController mDemoModeController; private final Handler mMainHandler; private final Handler mBgHandler; protected final Context mContext; @@ -82,15 +87,21 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC @VisibleForTesting @Inject - public BatteryControllerImpl(Context context, EnhancedEstimates enhancedEstimates, - PowerManager powerManager, BroadcastDispatcher broadcastDispatcher, - @Main Handler mainHandler, @Background Handler bgHandler) { + public BatteryControllerImpl( + Context context, + EnhancedEstimates enhancedEstimates, + PowerManager powerManager, + BroadcastDispatcher broadcastDispatcher, + DemoModeController demoModeController, + @Main Handler mainHandler, + @Background Handler bgHandler) { mContext = context; mMainHandler = mainHandler; mBgHandler = bgHandler; mPowerManager = powerManager; mEstimates = enhancedEstimates; mBroadcastDispatcher = broadcastDispatcher; + mDemoModeController = demoModeController; } private void registerReceiver() { @@ -114,6 +125,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC onReceive(mContext, intent); } } + mDemoModeController.addCallback(this); updatePowerSave(); updateEstimate(); } @@ -134,7 +146,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC } @Override - public void addCallback(BatteryController.BatteryStateChangeCallback cb) { + public void addCallback(@NonNull BatteryController.BatteryStateChangeCallback cb) { synchronized (mChangeCallbacks) { mChangeCallbacks.add(cb); } @@ -144,7 +156,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC } @Override - public void removeCallback(BatteryController.BatteryStateChangeCallback cb) { + public void removeCallback(@NonNull BatteryController.BatteryStateChangeCallback cb) { synchronized (mChangeCallbacks) { mChangeCallbacks.remove(cb); } @@ -325,32 +337,43 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC } } - private boolean mDemoMode; - @Override public void dispatchDemoCommand(String command, Bundle args) { - if (!mDemoMode && command.equals(COMMAND_ENTER)) { - mDemoMode = true; - mBroadcastDispatcher.unregisterReceiver(this); - } else if (mDemoMode && command.equals(COMMAND_EXIT)) { - mDemoMode = false; - registerReceiver(); - updatePowerSave(); - } else if (mDemoMode && command.equals(COMMAND_BATTERY)) { - String level = args.getString("level"); - String plugged = args.getString("plugged"); - String powerSave = args.getString("powersave"); - if (level != null) { - mLevel = Math.min(Math.max(Integer.parseInt(level), 0), 100); - } - if (plugged != null) { - mPluggedIn = Boolean.parseBoolean(plugged); - } - if (powerSave != null) { - mPowerSave = powerSave.equals("true"); - firePowerSaveChanged(); - } - fireBatteryLevelChanged(); + if (!mDemoModeController.isInDemoMode()) { + return; + } + + String level = args.getString("level"); + String plugged = args.getString("plugged"); + String powerSave = args.getString("powersave"); + if (level != null) { + mLevel = Math.min(Math.max(Integer.parseInt(level), 0), 100); + } + if (plugged != null) { + mPluggedIn = Boolean.parseBoolean(plugged); + } + if (powerSave != null) { + mPowerSave = powerSave.equals("true"); + firePowerSaveChanged(); } + fireBatteryLevelChanged(); + } + + @Override + public List<String> demoCommands() { + List<String> s = new ArrayList<>(); + s.add(DemoMode.COMMAND_BATTERY); + return s; + } + + @Override + public void onDemoModeStarted() { + mBroadcastDispatcher.unregisterReceiver(this); + } + + @Override + public void onDemoModeFinished() { + registerReceiver(); + updatePowerSave(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java index 0fc3d8481907..8110ab44f09d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java @@ -29,6 +29,8 @@ import android.os.UserHandle; import android.os.UserManager; import android.util.Log; +import androidx.annotation.NonNull; + import com.android.settingslib.bluetooth.BluetoothCallback; import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.LocalBluetoothManager; @@ -150,13 +152,13 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa } @Override - public void addCallback(Callback cb) { + public void addCallback(@NonNull Callback cb) { mHandler.obtainMessage(H.MSG_ADD_CALLBACK, cb).sendToTarget(); mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED); } @Override - public void removeCallback(Callback cb) { + public void removeCallback(@NonNull Callback cb) { mHandler.obtainMessage(H.MSG_REMOVE_CALLBACK, cb).sendToTarget(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java index 78111fb61fd0..a0b03e1c54c2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java @@ -123,13 +123,13 @@ public class BrightnessMirrorController } @Override - public void addCallback(BrightnessMirrorListener listener) { + public void addCallback(@NonNull BrightnessMirrorListener listener) { Objects.requireNonNull(listener); mBrightnessMirrorListeners.add(listener); } @Override - public void removeCallback(BrightnessMirrorListener listener) { + public void removeCallback(@NonNull BrightnessMirrorListener listener) { mBrightnessMirrorListeners.remove(listener); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackController.java index 626eef5867f2..047ff75468ed 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackController.java @@ -15,14 +15,19 @@ package com.android.systemui.statusbar.policy; +import androidx.annotation.NonNull; import androidx.lifecycle.Lifecycle; import androidx.lifecycle.Lifecycle.Event; import androidx.lifecycle.LifecycleEventObserver; import androidx.lifecycle.LifecycleOwner; public interface CallbackController<T> { - void addCallback(T listener); - void removeCallback(T listener); + + /** Add a callback */ + void addCallback(@NonNull T listener); + + /** Remove a callback */ + void removeCallback(@NonNull T listener); /** * Wrapper to {@link #addCallback(Object)} when a lifecycle is in the resumed state diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java index 6106f38c0e60..f38c73100292 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java @@ -31,6 +31,7 @@ import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; +import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import com.android.internal.annotations.GuardedBy; @@ -95,7 +96,7 @@ public class CastControllerImpl implements CastController { } @Override - public void addCallback(Callback callback) { + public void addCallback(@NonNull Callback callback) { synchronized (mCallbacks) { mCallbacks.add(callback); } @@ -106,7 +107,7 @@ public class CastControllerImpl implements CastController { } @Override - public void removeCallback(Callback callback) { + public void removeCallback(@NonNull Callback callback) { synchronized (mCallbacks) { mCallbacks.remove(callback); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java index 120a0e3abba4..ef35a3c55ab8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java @@ -40,11 +40,11 @@ import android.view.View; import android.widget.TextView; import com.android.settingslib.Utils; -import com.android.systemui.DemoMode; import com.android.systemui.Dependency; import com.android.systemui.FontSizeUtils; import com.android.systemui.R; import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.demomode.DemoModeCommandReceiver; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver; import com.android.systemui.settings.CurrentUserTracker; @@ -62,7 +62,10 @@ import java.util.TimeZone; /** * Digital clock for the status bar. */ -public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.Callbacks, +public class Clock extends TextView implements + DemoModeCommandReceiver, + Tunable, + CommandQueue.Callbacks, DarkReceiver, ConfigurationListener { public static final String CLOCK_SECONDS = "clock_seconds"; @@ -467,30 +470,35 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C @Override public void dispatchDemoCommand(String command, Bundle args) { - if (!mDemoMode && command.equals(COMMAND_ENTER)) { - mDemoMode = true; - } else if (mDemoMode && command.equals(COMMAND_EXIT)) { - mDemoMode = false; - updateClock(); - } else if (mDemoMode && command.equals(COMMAND_CLOCK)) { - String millis = args.getString("millis"); - String hhmm = args.getString("hhmm"); - if (millis != null) { - mCalendar.setTimeInMillis(Long.parseLong(millis)); - } else if (hhmm != null && hhmm.length() == 4) { - int hh = Integer.parseInt(hhmm.substring(0, 2)); - int mm = Integer.parseInt(hhmm.substring(2)); - boolean is24 = DateFormat.is24HourFormat(getContext(), mCurrentUserId); - if (is24) { - mCalendar.set(Calendar.HOUR_OF_DAY, hh); - } else { - mCalendar.set(Calendar.HOUR, hh); - } - mCalendar.set(Calendar.MINUTE, mm); + // Only registered for COMMAND_CLOCK + String millis = args.getString("millis"); + String hhmm = args.getString("hhmm"); + if (millis != null) { + mCalendar.setTimeInMillis(Long.parseLong(millis)); + } else if (hhmm != null && hhmm.length() == 4) { + int hh = Integer.parseInt(hhmm.substring(0, 2)); + int mm = Integer.parseInt(hhmm.substring(2)); + boolean is24 = DateFormat.is24HourFormat(getContext(), mCurrentUserId); + if (is24) { + mCalendar.set(Calendar.HOUR_OF_DAY, hh); + } else { + mCalendar.set(Calendar.HOUR, hh); } - setText(getSmallTime()); - setContentDescription(mContentDescriptionFormat.format(mCalendar.getTime())); + mCalendar.set(Calendar.MINUTE, mm); } + setText(getSmallTime()); + setContentDescription(mContentDescriptionFormat.format(mCalendar.getTime())); + } + + @Override + public void onDemoModeStarted() { + mDemoMode = true; + } + + @Override + public void onDemoModeFinished() { + mDemoMode = false; + updateClock(); } private final BroadcastReceiver mScreenReceiver = new BroadcastReceiver() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverControllerImpl.java index 911715fdba63..8207012af6cc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DataSaverControllerImpl.java @@ -21,6 +21,8 @@ import android.os.Handler; import android.os.Looper; import android.os.RemoteException; +import androidx.annotation.NonNull; + import java.util.ArrayList; public class DataSaverControllerImpl implements DataSaverController { @@ -41,7 +43,8 @@ public class DataSaverControllerImpl implements DataSaverController { } } - public void addCallback(Listener listener) { + @Override + public void addCallback(@NonNull Listener listener) { synchronized (mListeners) { mListeners.add(listener); if (mListeners.size() == 1) { @@ -51,7 +54,8 @@ public class DataSaverControllerImpl implements DataSaverController { listener.onDataSaverChanged(isDataSaverEnabled()); } - public void removeCallback(Listener listener) { + @Override + public void removeCallback(@NonNull Listener listener) { synchronized (mListeners) { mListeners.remove(listener); if (mListeners.size() == 0) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java index 7280a881655c..071f05a962d6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java @@ -24,6 +24,8 @@ import android.provider.Settings.Global; import android.provider.Settings.Secure; import android.util.Log; +import androidx.annotation.NonNull; + import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.settings.CurrentUserTracker; @@ -87,7 +89,7 @@ public class DeviceProvisionedControllerImpl extends CurrentUserTracker implemen } @Override - public void addCallback(DeviceProvisionedListener listener) { + public void addCallback(@NonNull DeviceProvisionedListener listener) { mListeners.add(listener); if (mListeners.size() == 1) { startListening(getCurrentUser()); @@ -97,7 +99,7 @@ public class DeviceProvisionedControllerImpl extends CurrentUserTracker implemen } @Override - public void removeCallback(DeviceProvisionedListener listener) { + public void removeCallback(@NonNull DeviceProvisionedListener listener) { mListeners.remove(listener); if (mListeners.size() == 0) { stopListening(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java index 41ff9d1029b2..659212c4d33d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java @@ -30,6 +30,8 @@ import android.provider.Settings.Secure; import android.text.TextUtils; import android.util.Log; +import androidx.annotation.NonNull; + import java.io.FileDescriptor; import java.io.PrintWriter; import java.lang.ref.WeakReference; @@ -123,7 +125,8 @@ public class FlashlightControllerImpl implements FlashlightController { return mTorchAvailable; } - public void addCallback(FlashlightListener l) { + @Override + public void addCallback(@NonNull FlashlightListener l) { synchronized (mListeners) { if (mCameraId == null) { tryInitCamera(); @@ -135,7 +138,8 @@ public class FlashlightControllerImpl implements FlashlightController { } } - public void removeCallback(FlashlightListener l) { + @Override + public void removeCallback(@NonNull FlashlightListener l) { synchronized (mListeners) { cleanUpListenersLocked(l); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java index 60ee75b534d8..1baed09d4e3c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java @@ -30,6 +30,8 @@ import android.os.HandlerExecutor; import android.os.UserManager; import android.util.Log; +import androidx.annotation.NonNull; + import com.android.internal.util.ConcurrentUtils; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; @@ -143,7 +145,7 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof * changes. It will immediately trigger the callback added to notify current state. */ @Override - public void addCallback(Callback callback) { + public void addCallback(@NonNull Callback callback) { synchronized (mCallbacks) { if (callback == null || mCallbacks.contains(callback)) return; if (DEBUG) Log.d(TAG, "addCallback " + callback); @@ -163,7 +165,7 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof } @Override - public void removeCallback(Callback callback) { + public void removeCallback(@NonNull Callback callback) { if (callback == null) return; if (DEBUG) Log.d(TAG, "removeCallback " + callback); synchronized (mCallbacks) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java index adfc14e1d72b..a995ade8dafe 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java @@ -33,6 +33,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; +import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import com.android.systemui.BootCompleteCache; @@ -87,12 +88,14 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio /** * Add a callback to listen for changes in location settings. */ - public void addCallback(LocationChangeCallback cb) { + @Override + public void addCallback(@NonNull LocationChangeCallback cb) { mHandler.obtainMessage(H.MSG_ADD_CALLBACK, cb).sendToTarget(); mHandler.sendEmptyMessage(H.MSG_LOCATION_SETTINGS_CHANGED); } - public void removeCallback(LocationChangeCallback cb) { + @Override + public void removeCallback(@NonNull LocationChangeCallback cb) { mHandler.obtainMessage(H.MSG_REMOVE_CALLBACK, cb).sendToTarget(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java index 95a97729936b..b790c92b293c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java @@ -22,7 +22,7 @@ import android.telephony.SubscriptionInfo; import com.android.settingslib.net.DataUsageController; import com.android.settingslib.wifi.AccessPoint; -import com.android.systemui.DemoMode; +import com.android.systemui.demomode.DemoMode; import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; import java.util.List; @@ -30,8 +30,6 @@ import java.util.List; public interface NetworkController extends CallbackController<SignalCallback>, DemoMode { boolean hasMobileDataFeature(); - void addCallback(SignalCallback cb); - void removeCallback(SignalCallback cb); void setWifiEnabled(boolean enabled); AccessPointController getAccessPointController(); DataUsageController getMobileDataController(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index 32c4aec39923..7a0f69067851 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -55,14 +55,17 @@ import android.util.Log; import android.util.MathUtils; import android.util.SparseArray; +import androidx.annotation.NonNull; + import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.settingslib.net.DataUsageController; -import com.android.systemui.DemoMode; import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.demomode.DemoMode; +import com.android.systemui.demomode.DemoModeController; import com.android.systemui.settings.CurrentUserTracker; import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener; @@ -104,6 +107,7 @@ public class NetworkControllerImpl extends BroadcastReceiver private final DataSaverController mDataSaverController; private final CurrentUserTracker mUserTracker; private final BroadcastDispatcher mBroadcastDispatcher; + private final DemoModeController mDemoModeController; private final Object mLock = new Object(); private Config mConfig; @@ -173,11 +177,16 @@ public class NetworkControllerImpl extends BroadcastReceiver * Construct this controller object and register for updates. */ @Inject - public NetworkControllerImpl(Context context, @Background Looper bgLooper, + public NetworkControllerImpl( + Context context, + @Background Looper bgLooper, DeviceProvisionedController deviceProvisionedController, - BroadcastDispatcher broadcastDispatcher, ConnectivityManager connectivityManager, - TelephonyManager telephonyManager, @Nullable WifiManager wifiManager, - NetworkScoreManager networkScoreManager) { + BroadcastDispatcher broadcastDispatcher, + ConnectivityManager connectivityManager, + TelephonyManager telephonyManager, + @Nullable WifiManager wifiManager, + NetworkScoreManager networkScoreManager, + DemoModeController demoModeController) { this(context, connectivityManager, telephonyManager, wifiManager, @@ -188,7 +197,8 @@ public class NetworkControllerImpl extends BroadcastReceiver new DataUsageController(context), new SubscriptionDefaults(), deviceProvisionedController, - broadcastDispatcher); + broadcastDispatcher, + demoModeController); mReceiverHandler.post(mRegisterListeners); } @@ -202,7 +212,8 @@ public class NetworkControllerImpl extends BroadcastReceiver DataUsageController dataUsageController, SubscriptionDefaults defaultsHandler, DeviceProvisionedController deviceProvisionedController, - BroadcastDispatcher broadcastDispatcher) { + BroadcastDispatcher broadcastDispatcher, + DemoModeController demoModeController) { mContext = context; mConfig = config; mReceiverHandler = new Handler(bgLooper); @@ -215,6 +226,7 @@ public class NetworkControllerImpl extends BroadcastReceiver mConnectivityManager = connectivityManager; mHasMobileDataFeature = mConnectivityManager.isNetworkSupported(ConnectivityManager.TYPE_MOBILE); + mDemoModeController = demoModeController; // telephony mPhone = telephonyManager; @@ -306,6 +318,8 @@ public class NetworkControllerImpl extends BroadcastReceiver doUpdateMobileControllers(); } }; + + mDemoModeController.addCallback(this); } private final Runnable mClearForceValidated = () -> { @@ -514,7 +528,8 @@ public class NetworkControllerImpl extends BroadcastReceiver mCallbackHandler.setEmergencyCallsOnly(mIsEmergency); } - public void addCallback(SignalCallback cb) { + @Override + public void addCallback(@NonNull SignalCallback cb) { cb.setSubs(mCurrentSubscriptions); cb.setIsAirplaneMode(new IconState(mAirplaneMode, TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, mContext)); @@ -529,7 +544,7 @@ public class NetworkControllerImpl extends BroadcastReceiver } @Override - public void removeCallback(SignalCallback cb) { + public void removeCallback(@NonNull SignalCallback cb) { mCallbackHandler.setListening(cb, false); } @@ -932,205 +947,217 @@ public class NetworkControllerImpl extends BroadcastReceiver return "UNKNOWN_SOURCE"; } - private boolean mDemoMode; private boolean mDemoInetCondition; private WifiSignalController.WifiState mDemoWifiState; @Override + public void onDemoModeStarted() { + if (DEBUG) Log.d(TAG, "Entering demo mode"); + unregisterListeners(); + mDemoInetCondition = mInetCondition; + mDemoWifiState = mWifiSignalController.getState(); + mDemoWifiState.ssid = "DemoMode"; + } + + @Override + public void onDemoModeFinished() { + if (DEBUG) Log.d(TAG, "Exiting demo mode"); + // Update what MobileSignalControllers, because they may change + // to set the number of sim slots. + updateMobileControllers(); + for (int i = 0; i < mMobileSignalControllers.size(); i++) { + MobileSignalController controller = mMobileSignalControllers.valueAt(i); + controller.resetLastState(); + } + mWifiSignalController.resetLastState(); + mReceiverHandler.post(mRegisterListeners); + notifyAllListeners(); + } + + @Override public void dispatchDemoCommand(String command, Bundle args) { - if (!mDemoMode && command.equals(COMMAND_ENTER)) { - if (DEBUG) Log.d(TAG, "Entering demo mode"); - unregisterListeners(); - mDemoMode = true; - mDemoInetCondition = mInetCondition; - mDemoWifiState = mWifiSignalController.getState(); - mDemoWifiState.ssid = "DemoMode"; - } else if (mDemoMode && command.equals(COMMAND_EXIT)) { - if (DEBUG) Log.d(TAG, "Exiting demo mode"); - mDemoMode = false; - // Update what MobileSignalControllers, because they may change - // to set the number of sim slots. - updateMobileControllers(); + if (!mDemoModeController.isInDemoMode()) { + return; + } + + String airplane = args.getString("airplane"); + if (airplane != null) { + boolean show = airplane.equals("show"); + mCallbackHandler.setIsAirplaneMode(new IconState(show, + TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, + mContext)); + } + String fully = args.getString("fully"); + if (fully != null) { + mDemoInetCondition = Boolean.parseBoolean(fully); + BitSet connected = new BitSet(); + + if (mDemoInetCondition) { + connected.set(mWifiSignalController.mTransportType); + } + mWifiSignalController.updateConnectivity(connected, connected); for (int i = 0; i < mMobileSignalControllers.size(); i++) { MobileSignalController controller = mMobileSignalControllers.valueAt(i); - controller.resetLastState(); - } - mWifiSignalController.resetLastState(); - mReceiverHandler.post(mRegisterListeners); - notifyAllListeners(); - } else if (mDemoMode && command.equals(COMMAND_NETWORK)) { - String airplane = args.getString("airplane"); - if (airplane != null) { - boolean show = airplane.equals("show"); - mCallbackHandler.setIsAirplaneMode(new IconState(show, - TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, - mContext)); - } - String fully = args.getString("fully"); - if (fully != null) { - mDemoInetCondition = Boolean.parseBoolean(fully); - BitSet connected = new BitSet(); - if (mDemoInetCondition) { - connected.set(mWifiSignalController.mTransportType); - } - mWifiSignalController.updateConnectivity(connected, connected); - for (int i = 0; i < mMobileSignalControllers.size(); i++) { - MobileSignalController controller = mMobileSignalControllers.valueAt(i); - if (mDemoInetCondition) { - connected.set(controller.mTransportType); - } - controller.updateConnectivity(connected, connected); + connected.set(controller.mTransportType); } + controller.updateConnectivity(connected, connected); } - String wifi = args.getString("wifi"); - if (wifi != null) { - boolean show = wifi.equals("show"); - String level = args.getString("level"); - if (level != null) { - mDemoWifiState.level = level.equals("null") ? -1 - : Math.min(Integer.parseInt(level), WifiIcons.WIFI_LEVEL_COUNT - 1); - mDemoWifiState.connected = mDemoWifiState.level >= 0; - } - String activity = args.getString("activity"); - if (activity != null) { - switch (activity) { - case "inout": - mWifiSignalController.setActivity(DATA_ACTIVITY_INOUT); - break; - case "in": - mWifiSignalController.setActivity(DATA_ACTIVITY_IN); - break; - case "out": - mWifiSignalController.setActivity(DATA_ACTIVITY_OUT); - break; - default: - mWifiSignalController.setActivity(DATA_ACTIVITY_NONE); - break; - } - } else { - mWifiSignalController.setActivity(DATA_ACTIVITY_NONE); - } - String ssid = args.getString("ssid"); - if (ssid != null) { - mDemoWifiState.ssid = ssid; - } - mDemoWifiState.enabled = show; - mWifiSignalController.notifyListeners(); + } + String wifi = args.getString("wifi"); + if (wifi != null) { + boolean show = wifi.equals("show"); + String level = args.getString("level"); + if (level != null) { + mDemoWifiState.level = level.equals("null") ? -1 + : Math.min(Integer.parseInt(level), WifiIcons.WIFI_LEVEL_COUNT - 1); + mDemoWifiState.connected = mDemoWifiState.level >= 0; } - String sims = args.getString("sims"); - if (sims != null) { - int num = MathUtils.constrain(Integer.parseInt(sims), 1, 8); - List<SubscriptionInfo> subs = new ArrayList<>(); - if (num != mMobileSignalControllers.size()) { - mMobileSignalControllers.clear(); - int start = mSubscriptionManager.getActiveSubscriptionInfoCountMax(); - for (int i = start /* get out of normal index range */; i < start + num; i++) { - subs.add(addSignalController(i, i)); - } - mCallbackHandler.setSubs(subs); - for (int i = 0; i < mMobileSignalControllers.size(); i++) { - int key = mMobileSignalControllers.keyAt(i); - MobileSignalController controller = mMobileSignalControllers.get(key); - controller.notifyListeners(); - } + String activity = args.getString("activity"); + if (activity != null) { + switch (activity) { + case "inout": + mWifiSignalController.setActivity(DATA_ACTIVITY_INOUT); + break; + case "in": + mWifiSignalController.setActivity(DATA_ACTIVITY_IN); + break; + case "out": + mWifiSignalController.setActivity(DATA_ACTIVITY_OUT); + break; + default: + mWifiSignalController.setActivity(DATA_ACTIVITY_NONE); + break; } + } else { + mWifiSignalController.setActivity(DATA_ACTIVITY_NONE); } - String nosim = args.getString("nosim"); - if (nosim != null) { - mHasNoSubs = nosim.equals("show"); - mCallbackHandler.setNoSims(mHasNoSubs, mSimDetected); + String ssid = args.getString("ssid"); + if (ssid != null) { + mDemoWifiState.ssid = ssid; } - String mobile = args.getString("mobile"); - if (mobile != null) { - boolean show = mobile.equals("show"); - String datatype = args.getString("datatype"); - String slotString = args.getString("slot"); - int slot = TextUtils.isEmpty(slotString) ? 0 : Integer.parseInt(slotString); - slot = MathUtils.constrain(slot, 0, 8); - // Ensure we have enough sim slots - List<SubscriptionInfo> subs = new ArrayList<>(); - while (mMobileSignalControllers.size() <= slot) { - int nextSlot = mMobileSignalControllers.size(); - subs.add(addSignalController(nextSlot, nextSlot)); - } - if (!subs.isEmpty()) { - mCallbackHandler.setSubs(subs); - } - // Hack to index linearly for easy use. - MobileSignalController controller = mMobileSignalControllers.valueAt(slot); - controller.getState().dataSim = datatype != null; - controller.getState().isDefault = datatype != null; - controller.getState().dataConnected = datatype != null; - if (datatype != null) { - controller.getState().iconGroup = - datatype.equals("1x") ? TelephonyIcons.ONE_X : - datatype.equals("3g") ? TelephonyIcons.THREE_G : - datatype.equals("4g") ? TelephonyIcons.FOUR_G : - datatype.equals("4g+") ? TelephonyIcons.FOUR_G_PLUS : - datatype.equals("5g") ? TelephonyIcons.NR_5G : - datatype.equals("5ge") ? TelephonyIcons.LTE_CA_5G_E : - datatype.equals("5g+") ? TelephonyIcons.NR_5G_PLUS : - datatype.equals("e") ? TelephonyIcons.E : - datatype.equals("g") ? TelephonyIcons.G : - datatype.equals("h") ? TelephonyIcons.H : - datatype.equals("h+") ? TelephonyIcons.H_PLUS : - datatype.equals("lte") ? TelephonyIcons.LTE : - datatype.equals("lte+") ? TelephonyIcons.LTE_PLUS : - datatype.equals("dis") ? TelephonyIcons.DATA_DISABLED : - datatype.equals("not") ? TelephonyIcons.NOT_DEFAULT_DATA : - TelephonyIcons.UNKNOWN; - } - if (args.containsKey("roam")) { - controller.getState().roaming = "show".equals(args.getString("roam")); - } - String level = args.getString("level"); - if (level != null) { - controller.getState().level = level.equals("null") ? -1 - : Math.min(Integer.parseInt(level), - CellSignalStrength.getNumSignalStrengthLevels()); - controller.getState().connected = controller.getState().level >= 0; - } - if (args.containsKey("inflate")) { - for (int i = 0; i < mMobileSignalControllers.size(); i++) { - mMobileSignalControllers.valueAt(i).mInflateSignalStrengths = - "true".equals(args.getString("inflate")); - } + mDemoWifiState.enabled = show; + mWifiSignalController.notifyListeners(); + } + String sims = args.getString("sims"); + if (sims != null) { + int num = MathUtils.constrain(Integer.parseInt(sims), 1, 8); + List<SubscriptionInfo> subs = new ArrayList<>(); + if (num != mMobileSignalControllers.size()) { + mMobileSignalControllers.clear(); + int start = mSubscriptionManager.getActiveSubscriptionInfoCountMax(); + for (int i = start /* get out of normal index range */; i < start + num; i++) { + subs.add(addSignalController(i, i)); } - String activity = args.getString("activity"); - if (activity != null) { - controller.getState().dataConnected = true; - switch (activity) { - case "inout": - controller.setActivity(TelephonyManager.DATA_ACTIVITY_INOUT); - break; - case "in": - controller.setActivity(TelephonyManager.DATA_ACTIVITY_IN); - break; - case "out": - controller.setActivity(TelephonyManager.DATA_ACTIVITY_OUT); - break; - default: - controller.setActivity(TelephonyManager.DATA_ACTIVITY_NONE); - break; - } - } else { - controller.setActivity(TelephonyManager.DATA_ACTIVITY_NONE); + mCallbackHandler.setSubs(subs); + for (int i = 0; i < mMobileSignalControllers.size(); i++) { + int key = mMobileSignalControllers.keyAt(i); + MobileSignalController controller = mMobileSignalControllers.get(key); + controller.notifyListeners(); } - controller.getState().enabled = show; - controller.notifyListeners(); } - String carrierNetworkChange = args.getString("carriernetworkchange"); - if (carrierNetworkChange != null) { - boolean show = carrierNetworkChange.equals("show"); + } + String nosim = args.getString("nosim"); + if (nosim != null) { + mHasNoSubs = nosim.equals("show"); + mCallbackHandler.setNoSims(mHasNoSubs, mSimDetected); + } + String mobile = args.getString("mobile"); + if (mobile != null) { + boolean show = mobile.equals("show"); + String datatype = args.getString("datatype"); + String slotString = args.getString("slot"); + int slot = TextUtils.isEmpty(slotString) ? 0 : Integer.parseInt(slotString); + slot = MathUtils.constrain(slot, 0, 8); + // Ensure we have enough sim slots + List<SubscriptionInfo> subs = new ArrayList<>(); + while (mMobileSignalControllers.size() <= slot) { + int nextSlot = mMobileSignalControllers.size(); + subs.add(addSignalController(nextSlot, nextSlot)); + } + if (!subs.isEmpty()) { + mCallbackHandler.setSubs(subs); + } + // Hack to index linearly for easy use. + MobileSignalController controller = mMobileSignalControllers.valueAt(slot); + controller.getState().dataSim = datatype != null; + controller.getState().isDefault = datatype != null; + controller.getState().dataConnected = datatype != null; + if (datatype != null) { + controller.getState().iconGroup = + datatype.equals("1x") ? TelephonyIcons.ONE_X : + datatype.equals("3g") ? TelephonyIcons.THREE_G : + datatype.equals("4g") ? TelephonyIcons.FOUR_G : + datatype.equals("4g+") ? TelephonyIcons.FOUR_G_PLUS : + datatype.equals("5g") ? TelephonyIcons.NR_5G : + datatype.equals("5ge") ? TelephonyIcons.LTE_CA_5G_E : + datatype.equals("5g+") ? TelephonyIcons.NR_5G_PLUS : + datatype.equals("e") ? TelephonyIcons.E : + datatype.equals("g") ? TelephonyIcons.G : + datatype.equals("h") ? TelephonyIcons.H : + datatype.equals("h+") ? TelephonyIcons.H_PLUS : + datatype.equals("lte") ? TelephonyIcons.LTE : + datatype.equals("lte+") ? TelephonyIcons.LTE_PLUS : + datatype.equals("dis") ? TelephonyIcons.DATA_DISABLED : + datatype.equals("not") ? TelephonyIcons.NOT_DEFAULT_DATA : + TelephonyIcons.UNKNOWN; + } + if (args.containsKey("roam")) { + controller.getState().roaming = "show".equals(args.getString("roam")); + } + String level = args.getString("level"); + if (level != null) { + controller.getState().level = level.equals("null") ? -1 + : Math.min(Integer.parseInt(level), + CellSignalStrength.getNumSignalStrengthLevels()); + controller.getState().connected = controller.getState().level >= 0; + } + if (args.containsKey("inflate")) { for (int i = 0; i < mMobileSignalControllers.size(); i++) { - MobileSignalController controller = mMobileSignalControllers.valueAt(i); - controller.setCarrierNetworkChangeMode(show); + mMobileSignalControllers.valueAt(i).mInflateSignalStrengths = + "true".equals(args.getString("inflate")); } } + String activity = args.getString("activity"); + if (activity != null) { + controller.getState().dataConnected = true; + switch (activity) { + case "inout": + controller.setActivity(TelephonyManager.DATA_ACTIVITY_INOUT); + break; + case "in": + controller.setActivity(TelephonyManager.DATA_ACTIVITY_IN); + break; + case "out": + controller.setActivity(TelephonyManager.DATA_ACTIVITY_OUT); + break; + default: + controller.setActivity(TelephonyManager.DATA_ACTIVITY_NONE); + break; + } + } else { + controller.setActivity(TelephonyManager.DATA_ACTIVITY_NONE); + } + controller.getState().enabled = show; + controller.notifyListeners(); + } + String carrierNetworkChange = args.getString("carriernetworkchange"); + if (carrierNetworkChange != null) { + boolean show = carrierNetworkChange.equals("show"); + for (int i = 0; i < mMobileSignalControllers.size(); i++) { + MobileSignalController controller = mMobileSignalControllers.valueAt(i); + controller.setCarrierNetworkChangeMode(show); + } } } + @Override + public List<String> demoCommands() { + List<String> s = new ArrayList<>(); + s.add(DemoMode.COMMAND_NETWORK); + return s; + } + private SubscriptionInfo addSignalController(int id, int simSlotIndex) { SubscriptionInfo info = new SubscriptionInfo(id, "", simSlotIndex, "", "", 0, 0, "", 0, null, null, null, "", false, null, null); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmControllerImpl.java index 288b3aff2af6..604e76e46ab5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmControllerImpl.java @@ -23,6 +23,8 @@ import android.content.Intent; import android.content.IntentFilter; import android.os.UserHandle; +import androidx.annotation.NonNull; + import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; @@ -59,12 +61,14 @@ public class NextAlarmControllerImpl extends BroadcastReceiver pw.print(" mNextAlarm="); pw.println(mNextAlarm); } - public void addCallback(NextAlarmChangeCallback cb) { + @Override + public void addCallback(@NonNull NextAlarmChangeCallback cb) { mChangeCallbacks.add(cb); cb.onNextAlarmChanged(mNextAlarm); } - public void removeCallback(NextAlarmChangeCallback cb) { + @Override + public void removeCallback(@NonNull NextAlarmChangeCallback cb) { mChangeCallbacks.remove(cb); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java index 1f368e164678..58bb64bbba5a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java @@ -19,6 +19,8 @@ package com.android.systemui.statusbar.policy; import android.content.Context; import android.os.UserHandle; +import androidx.annotation.NonNull; + import com.android.internal.view.RotationPolicy; import java.util.concurrent.CopyOnWriteArrayList; @@ -47,12 +49,14 @@ public final class RotationLockControllerImpl implements RotationLockController setListening(true); } - public void addCallback(RotationLockControllerCallback callback) { + @Override + public void addCallback(@NonNull RotationLockControllerCallback callback) { mCallbacks.add(callback); notifyChanged(callback); } - public void removeCallback(RotationLockControllerCallback callback) { + @Override + public void removeCallback(@NonNull RotationLockControllerCallback callback) { mCallbacks.remove(callback); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java index 309d4b04ebbf..d1a7a7b07a65 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java @@ -42,6 +42,8 @@ import android.util.Log; import android.util.Pair; import android.util.SparseArray; +import androidx.annotation.NonNull; + import com.android.internal.annotations.GuardedBy; import com.android.internal.net.LegacyVpnInfo; import com.android.internal.net.VpnConfig; @@ -274,7 +276,7 @@ public class SecurityControllerImpl extends CurrentUserTracker implements Securi } @Override - public void removeCallback(SecurityControllerCallback callback) { + public void removeCallback(@NonNull SecurityControllerCallback callback) { synchronized (mCallbacks) { if (callback == null) return; if (DEBUG) Log.d(TAG, "removeCallback " + callback); @@ -283,7 +285,7 @@ public class SecurityControllerImpl extends CurrentUserTracker implements Securi } @Override - public void addCallback(SecurityControllerCallback callback) { + public void addCallback(@NonNull SecurityControllerCallback callback) { synchronized (mCallbacks) { if (callback == null || mCallbacks.contains(callback)) return; if (DEBUG) Log.d(TAG, "addCallback " + callback); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyControllerImpl.java index 5db66932d3c1..cbafedc40d7e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensorPrivacyControllerImpl.java @@ -19,6 +19,8 @@ package com.android.systemui.statusbar.policy; import android.content.Context; import android.hardware.SensorPrivacyManager; +import androidx.annotation.NonNull; + import java.util.ArrayList; import java.util.List; @@ -60,7 +62,7 @@ public class SensorPrivacyControllerImpl implements SensorPrivacyController, /** * Adds the provided listener for callbacks when sensor privacy state changes. */ - public void addCallback(OnSensorPrivacyChangedListener listener) { + public void addCallback(@NonNull OnSensorPrivacyChangedListener listener) { synchronized (mLock) { mListeners.add(listener); notifyListenerLocked(listener); @@ -70,7 +72,7 @@ public class SensorPrivacyControllerImpl implements SensorPrivacyController, /** * Removes the provided listener from callbacks when sensor privacy state changes. */ - public void removeCallback(OnSensorPrivacyChangedListener listener) { + public void removeCallback(@NonNull OnSensorPrivacyChangedListener listener) { synchronized (mLock) { mListeners.remove(listener); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoControllerImpl.java index 0ca6ff6ec66e..6b2820d8d97d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoControllerImpl.java @@ -34,6 +34,8 @@ import android.os.UserManager; import android.provider.ContactsContract; import android.util.Log; +import androidx.annotation.NonNull; + import com.android.internal.util.UserIcons; import com.android.settingslib.drawable.UserIconDrawable; import com.android.systemui.R; @@ -75,12 +77,14 @@ public class UserInfoControllerImpl implements UserInfoController { null, null); } - public void addCallback(OnUserInfoChangedListener callback) { + @Override + public void addCallback(@NonNull OnUserInfoChangedListener callback) { mCallbacks.add(callback); callback.onUserInfoChanged(mUserName, mUserDrawable, mUserAccount); } - public void removeCallback(OnUserInfoChangedListener callback) { + @Override + public void removeCallback(@NonNull OnUserInfoChangedListener callback) { mCallbacks.remove(callback); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java index 4376a0145826..75c1e33203b6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java @@ -37,6 +37,8 @@ import android.service.notification.ZenModeConfig.ZenRule; import android.text.format.DateFormat; import android.util.Log; +import androidx.annotation.NonNull; + import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.Dumpable; import com.android.systemui.broadcast.BroadcastDispatcher; @@ -124,14 +126,14 @@ public class ZenModeControllerImpl extends CurrentUserTracker } @Override - public void addCallback(Callback callback) { + public void addCallback(@NonNull Callback callback) { synchronized (mCallbacksLock) { mCallbacks.add(callback); } } @Override - public void removeCallback(Callback callback) { + public void removeCallback(@NonNull Callback callback) { synchronized (mCallbacksLock) { mCallbacks.remove(callback); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java index e3eed35f0483..d4c6f4d6232a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.tv.micdisclosure; +import static android.provider.DeviceConfig.NAMESPACE_PRIVACY; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import android.animation.Animator; @@ -27,9 +28,8 @@ import android.annotation.UiThread; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; -import android.database.ContentObserver; import android.graphics.PixelFormat; -import android.provider.Settings; +import android.provider.DeviceConfig; import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; @@ -46,7 +46,9 @@ import com.android.systemui.statusbar.tv.TvStatusBar; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; +import java.util.Collections; import java.util.LinkedList; +import java.util.List; import java.util.Queue; import java.util.Set; @@ -65,9 +67,9 @@ public class AudioRecordingDisclosureBar implements // CtsSystemUiHostTestCases:TvMicrophoneCaptureIndicatorTest private static final String LAYOUT_PARAMS_TITLE = "MicrophoneCaptureIndicator"; - private static final String ENABLE_FLAG = "sysui_mic_disclosure_enable"; - private static final String EXEMPT_PACKAGES_LIST = "sysui_mic_disclosure_exempt"; - private static final String FORCED_PACKAGES_LIST = "sysui_mic_disclosure_forced"; + private static final String ENABLED_FLAG = "mic_disclosure_enabled"; + private static final String EXEMPT_PACKAGES_LIST = "mic_disclosure_exempt_packages"; + private static final String FORCED_PACKAGES_LIST = "mic_disclosure_forced_packages"; @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = {"STATE_"}, value = { @@ -95,7 +97,7 @@ public class AudioRecordingDisclosureBar implements private static final int MAXIMIZED_DURATION = 3000; private final Context mContext; - private boolean mIsEnabledInSettings; + private boolean mIsEnabled; private View mIndicatorView; private View mIconTextsContainer; @@ -141,26 +143,37 @@ public class AudioRecordingDisclosureBar implements * Set of applications for which we make an exception and do not show the indicator. This gets * populated once - in {@link #AudioRecordingDisclosureBar(Context)}. */ - private final Set<String> mExemptPackages; + private final Set<String> mExemptPackages = new ArraySet<>(); public AudioRecordingDisclosureBar(Context context) { mContext = context; - // Loading configs + // Load configs mRevealRecordingPackages = mContext.getResources().getBoolean( R.bool.audio_recording_disclosure_reveal_packages); - mExemptPackages = new ArraySet<>( - Arrays.asList(mContext.getResources().getStringArray( - R.array.audio_recording_disclosure_exempt_apps))); - mExemptPackages.addAll(Arrays.asList(getGlobalStringArray(EXEMPT_PACKAGES_LIST))); - mExemptPackages.removeAll(Arrays.asList(getGlobalStringArray(FORCED_PACKAGES_LIST))); - - // Check setting, and start if enabled - mIsEnabledInSettings = checkIfEnabledInSettings(); - registerSettingsObserver(); - if (mIsEnabledInSettings) { + reloadExemptPackages(); + + mIsEnabled = DeviceConfig.getBoolean(NAMESPACE_PRIVACY, ENABLED_FLAG, true); + // Start if enabled + if (mIsEnabled) { start(); } + + // Set up a config change listener + DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_PRIVACY, mContext.getMainExecutor(), + mConfigChangeListener); + } + + private void reloadExemptPackages() { + mExemptPackages.clear(); + mExemptPackages.addAll(Arrays.asList(mContext.getResources().getStringArray( + R.array.audio_recording_disclosure_exempt_apps))); + mExemptPackages.addAll( + splitByComma( + DeviceConfig.getString(NAMESPACE_PRIVACY, EXEMPT_PACKAGES_LIST, null))); + mExemptPackages.removeAll( + splitByComma( + DeviceConfig.getString(NAMESPACE_PRIVACY, FORCED_PACKAGES_LIST, null))); } @UiThread @@ -485,13 +498,11 @@ public class AudioRecordingDisclosureBar implements mState = STATE_MINIMIZED; - if (mRevealRecordingPackages) { - if (!mPendingNotificationPackages.isEmpty()) { - // There is a new application that started recording, tell the user about it. - expand(mPendingNotificationPackages.poll()); - } else { - hideIndicatorIfNeeded(); - } + if (mRevealRecordingPackages && !mPendingNotificationPackages.isEmpty()) { + // There is a new application that started recording, tell the user about it. + expand(mPendingNotificationPackages.poll()); + } else { + hideIndicatorIfNeeded(); } } @@ -525,11 +536,6 @@ public class AudioRecordingDisclosureBar implements mBgEnd = null; } - private String[] getGlobalStringArray(String setting) { - String result = Settings.Global.getString(mContext.getContentResolver(), setting); - return TextUtils.isEmpty(result) ? new String[0] : result.split(","); - } - private String getApplicationLabel(String packageName) { assertRevealingRecordingPackages(); @@ -550,32 +556,26 @@ public class AudioRecordingDisclosureBar implements } } - private boolean checkIfEnabledInSettings() { - // 0 = disabled, everything else = enabled. Enabled by default. - return Settings.Global.getInt(mContext.getContentResolver(), - ENABLE_FLAG, 1) != 0; + private static List<String> splitByComma(String string) { + return TextUtils.isEmpty(string) ? Collections.emptyList() : Arrays.asList( + string.split(",")); } - private void registerSettingsObserver() { - final ContentObserver contentObserver = new ContentObserver( - mContext.getMainThreadHandler()) { - @Override - public void onChange(boolean selfChange) { - if (mIsEnabledInSettings == checkIfEnabledInSettings()) { - // Nothing changed as we know it - ignore. - return; - } - - // Things changed: flip the flag. - mIsEnabledInSettings = !mIsEnabledInSettings; - if (mIsEnabledInSettings) { - start(); - } else { - stop(); + private final DeviceConfig.OnPropertiesChangedListener mConfigChangeListener = + new DeviceConfig.OnPropertiesChangedListener() { + @Override + public void onPropertiesChanged(DeviceConfig.Properties properties) { + reloadExemptPackages(); + + // Check if was enabled/disabled + if (mIsEnabled != properties.getBoolean(ENABLED_FLAG, true)) { + mIsEnabled = !mIsEnabled; + if (mIsEnabled) { + start(); + } else { + stop(); + } + } } - } - }; - mContext.getContentResolver().registerContentObserver( - Settings.Global.getUriFor(ENABLE_FLAG), false, contentObserver); - } + }; } diff --git a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java index 49ada1a5e41e..1f444340653d 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java @@ -15,14 +15,10 @@ */ package com.android.systemui.tuner; -import android.content.ContentResolver; +import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; -import android.database.ContentObserver; import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.provider.Settings; import android.view.MenuItem; import androidx.preference.Preference; @@ -33,13 +29,13 @@ import androidx.preference.SwitchPreference; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.systemui.DemoMode; import com.android.systemui.R; +import com.android.systemui.demomode.DemoMode; +import com.android.systemui.demomode.DemoModeAvailabilityTracker; +import com.android.systemui.demomode.DemoModeController; public class DemoModeFragment extends PreferenceFragment implements OnPreferenceChangeListener { - private static final String DEMO_MODE_ON = "sysui_tuner_demo_on"; - private static final String[] STATUS_ICONS = { "volume", "bluetooth", @@ -57,6 +53,17 @@ public class DemoModeFragment extends PreferenceFragment implements OnPreference private SwitchPreference mEnabledSwitch; private SwitchPreference mOnSwitch; + private DemoModeController mDemoModeController; + private Tracker mDemoModeTracker; + + // We are the only ones who ever call this constructor, so don't worry about the warning + @SuppressLint("ValidFragment") + public DemoModeFragment(DemoModeController demoModeController) { + super(); + mDemoModeController = demoModeController; + } + + @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { Context context = getContext(); @@ -73,13 +80,11 @@ public class DemoModeFragment extends PreferenceFragment implements OnPreference screen.addPreference(mOnSwitch); setPreferenceScreen(screen); + mDemoModeTracker = new Tracker(context); + mDemoModeTracker.startTracking(); updateDemoModeEnabled(); updateDemoModeOn(); - ContentResolver contentResolver = getContext().getContentResolver(); - contentResolver.registerContentObserver(Settings.Global.getUriFor( - DemoMode.DEMO_MODE_ALLOWED), false, mDemoModeObserver); - contentResolver.registerContentObserver(Settings.Global.getUriFor(DEMO_MODE_ON), false, - mDemoModeObserver); + setHasOptionsMenu(true); } @@ -107,21 +112,17 @@ public class DemoModeFragment extends PreferenceFragment implements OnPreference @Override public void onDestroy() { - getContext().getContentResolver().unregisterContentObserver(mDemoModeObserver); + mDemoModeTracker.stopTracking(); super.onDestroy(); } private void updateDemoModeEnabled() { - boolean enabled = Settings.Global.getInt(getContext().getContentResolver(), - DemoMode.DEMO_MODE_ALLOWED, 0) != 0; - mEnabledSwitch.setChecked(enabled); - mOnSwitch.setEnabled(enabled); + mEnabledSwitch.setChecked(mDemoModeTracker.isDemoModeAvailable()); + mOnSwitch.setEnabled(mDemoModeTracker.isDemoModeAvailable()); } private void updateDemoModeOn() { - boolean enabled = Settings.Global.getInt(getContext().getContentResolver(), - DEMO_MODE_ON, 0) != 0; - mOnSwitch.setChecked(enabled); + mOnSwitch.setChecked(mDemoModeTracker.isInDemoMode()); } @Override @@ -134,7 +135,7 @@ public class DemoModeFragment extends PreferenceFragment implements OnPreference stopDemoMode(); } MetricsLogger.action(getContext(), MetricsEvent.TUNER_DEMO_MODE_ENABLED, enabled); - setGlobal(DemoMode.DEMO_MODE_ALLOWED, enabled ? 1 : 0); + mDemoModeController.requestSetDemoModeAllowed(enabled); } else if (preference == mOnSwitch) { MetricsLogger.action(getContext(), MetricsEvent.TUNER_DEMO_MODE_ON, enabled); if (enabled) { @@ -151,11 +152,11 @@ public class DemoModeFragment extends PreferenceFragment implements OnPreference private void startDemoMode() { Intent intent = new Intent(DemoMode.ACTION_DEMO); - intent.putExtra(DemoMode.EXTRA_COMMAND, DemoMode.COMMAND_ENTER); - getContext().sendBroadcast(intent); + mDemoModeController.requestStartDemoMode(); intent.putExtra(DemoMode.EXTRA_COMMAND, DemoMode.COMMAND_CLOCK); + //TODO: everything below should move to DemoModeController, or some `initialState` command String demoTime = "1010"; // 10:10, a classic choice of horologists try { String[] versionParts = android.os.Build.VERSION.RELEASE_OR_CODENAME.split("\\."); @@ -194,25 +195,31 @@ public class DemoModeFragment extends PreferenceFragment implements OnPreference intent.putExtra("visible", "false"); getContext().sendBroadcast(intent); - setGlobal(DEMO_MODE_ON, 1); } private void stopDemoMode() { - Intent intent = new Intent(DemoMode.ACTION_DEMO); - intent.putExtra(DemoMode.EXTRA_COMMAND, DemoMode.COMMAND_EXIT); - getContext().sendBroadcast(intent); - setGlobal(DEMO_MODE_ON, 0); + mDemoModeController.requestFinishDemoMode(); } - private void setGlobal(String key, int value) { - Settings.Global.putInt(getContext().getContentResolver(), key, value); - } + private class Tracker extends DemoModeAvailabilityTracker { + Tracker(Context context) { + super(context); + } - private final ContentObserver mDemoModeObserver = - new ContentObserver(new Handler(Looper.getMainLooper())) { - public void onChange(boolean selfChange) { + @Override + public void onDemoModeAvailabilityChanged() { updateDemoModeEnabled(); updateDemoModeOn(); - }; + } + + @Override + public void onDemoModeStarted() { + updateDemoModeOn(); + } + + @Override + public void onDemoModeFinished() { + updateDemoModeOn(); + } }; } diff --git a/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java b/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java index fa531b5243b4..87d2063d18e9 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java @@ -14,18 +14,18 @@ package com.android.systemui.tuner; -import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY; -import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY_CODE_END; -import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY_CODE_START; -import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.KEY_IMAGE_DELIM; -import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.MENU_IME_ROTATE; -import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.NAVSPACE; -import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.NAV_BAR_LEFT; -import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.NAV_BAR_RIGHT; -import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.NAV_BAR_VIEWS; -import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.extractButton; -import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.extractImage; -import static com.android.systemui.statusbar.phone.NavigationBarInflaterView.extractKeycode; +import static com.android.systemui.navigationbar.NavigationBarInflaterView.KEY; +import static com.android.systemui.navigationbar.NavigationBarInflaterView.KEY_CODE_END; +import static com.android.systemui.navigationbar.NavigationBarInflaterView.KEY_CODE_START; +import static com.android.systemui.navigationbar.NavigationBarInflaterView.KEY_IMAGE_DELIM; +import static com.android.systemui.navigationbar.NavigationBarInflaterView.MENU_IME_ROTATE; +import static com.android.systemui.navigationbar.NavigationBarInflaterView.NAVSPACE; +import static com.android.systemui.navigationbar.NavigationBarInflaterView.NAV_BAR_LEFT; +import static com.android.systemui.navigationbar.NavigationBarInflaterView.NAV_BAR_RIGHT; +import static com.android.systemui.navigationbar.NavigationBarInflaterView.NAV_BAR_VIEWS; +import static com.android.systemui.navigationbar.NavigationBarInflaterView.extractButton; +import static com.android.systemui.navigationbar.NavigationBarInflaterView.extractImage; +import static com.android.systemui.navigationbar.NavigationBarInflaterView.extractKeycode; import android.annotation.Nullable; import android.app.AlertDialog; @@ -51,6 +51,7 @@ import com.android.systemui.tuner.TunerService.Tunable; import java.util.ArrayList; +@Deprecated public class NavBarTuner extends TunerPreferenceFragment { private static final String LAYOUT = "layout"; diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java index 453c2f7da71f..78341edefbb2 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java @@ -31,6 +31,7 @@ import androidx.preference.PreferenceScreen; import com.android.systemui.Dependency; import com.android.systemui.R; +import com.android.systemui.demomode.DemoModeController; import com.android.systemui.fragments.FragmentService; import javax.inject.Inject; @@ -41,9 +42,12 @@ public class TunerActivity extends Activity implements private static final String TAG_TUNER = "tuner"; + private final DemoModeController mDemoModeController; + @Inject - TunerActivity() { + TunerActivity(DemoModeController demoModeController) { super(); + mDemoModeController = demoModeController; } protected void onCreate(Bundle savedInstanceState) { @@ -61,7 +65,8 @@ public class TunerActivity extends Activity implements final String action = getIntent().getAction(); boolean showDemoMode = action != null && action.equals( "com.android.settings.action.DEMO_MODE"); - final PreferenceFragment fragment = showDemoMode ? new DemoModeFragment() + final PreferenceFragment fragment = showDemoMode + ? new DemoModeFragment(mDemoModeController) : new TunerFragment(); getFragmentManager().beginTransaction().replace(R.id.content_frame, fragment, TAG_TUNER).commit(); diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java index 644f7582f146..12dced7cc7b1 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java @@ -18,7 +18,6 @@ package com.android.systemui.tuner; import android.app.ActivityManager; import android.content.ContentResolver; import android.content.Context; -import android.content.Intent; import android.content.pm.UserInfo; import android.database.ContentObserver; import android.net.Uri; @@ -33,9 +32,9 @@ import android.util.ArraySet; import com.android.internal.util.ArrayUtils; import com.android.systemui.DejankUtils; -import com.android.systemui.DemoMode; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.demomode.DemoModeController; import com.android.systemui.qs.QSTileHost; import com.android.systemui.settings.CurrentUserTracker; import com.android.systemui.statusbar.phone.StatusBarIconController; @@ -54,6 +53,7 @@ import javax.inject.Singleton; @Singleton public class TunerServiceImpl extends TunerService { + private static final String TAG = "TunerService"; private static final String TUNER_VERSION = "sysui_tuner_version"; private static final int CURRENT_TUNER_VERSION = 4; @@ -63,7 +63,8 @@ public class TunerServiceImpl extends TunerService { private static final String[] RESET_EXCEPTION_LIST = new String[] { QSTileHost.TILES_SETTING, Settings.Secure.DOZE_ALWAYS_ON, - Settings.Secure.MEDIA_CONTROLS_RESUME + Settings.Secure.MEDIA_CONTROLS_RESUME, + Secure.MEDIA_CONTROLS_RESUME_BLOCKED }; private final Observer mObserver = new Observer(); @@ -76,6 +77,7 @@ public class TunerServiceImpl extends TunerService { private final HashSet<Tunable> mTunables = LeakDetector.ENABLED ? new HashSet<>() : null; private final Context mContext; private final LeakDetector mLeakDetector; + private final DemoModeController mDemoModeController; private ContentResolver mContentResolver; private int mCurrentUser; @@ -84,11 +86,16 @@ public class TunerServiceImpl extends TunerService { /** */ @Inject - public TunerServiceImpl(Context context, @Main Handler mainHandler, - LeakDetector leakDetector, BroadcastDispatcher broadcastDispatcher) { + public TunerServiceImpl( + Context context, + @Main Handler mainHandler, + LeakDetector leakDetector, + DemoModeController demoModeController, + BroadcastDispatcher broadcastDispatcher) { mContext = context; mContentResolver = mContext.getContentResolver(); mLeakDetector = leakDetector; + mDemoModeController = demoModeController; for (UserInfo user : UserManager.get(mContext).getUsers()) { mCurrentUser = user.getUserHandle().getIdentifier(); @@ -244,12 +251,11 @@ public class TunerServiceImpl extends TunerService { } public void clearAllFromUser(int user) { - // A couple special cases. - Settings.Global.putString(mContentResolver, DemoMode.DEMO_MODE_ALLOWED, null); - Intent intent = new Intent(DemoMode.ACTION_DEMO); - intent.putExtra(DemoMode.EXTRA_COMMAND, DemoMode.COMMAND_EXIT); - mContext.sendBroadcast(intent); + // Turn off demo mode + mDemoModeController.requestFinishDemoMode(); + mDemoModeController.requestSetDemoModeAllowed(false); + // A couple special cases. for (String key : mTunableLookup.keySet()) { if (ArrayUtils.contains(RESET_EXCEPTION_LIST, key)) { continue; diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIRootComponent.java b/packages/SystemUI/src/com/android/systemui/tv/TvGlobalRootComponent.java index dce38c109930..fd6ba1a6af0e 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIRootComponent.java +++ b/packages/SystemUI/src/com/android/systemui/tv/TvGlobalRootComponent.java @@ -19,11 +19,10 @@ package com.android.systemui.tv; import com.android.systemui.dagger.DefaultComponentBinder; import com.android.systemui.dagger.DependencyBinder; import com.android.systemui.dagger.DependencyProvider; +import com.android.systemui.dagger.GlobalRootComponent; import com.android.systemui.dagger.SystemServicesModule; import com.android.systemui.dagger.SystemUIBinder; -import com.android.systemui.dagger.SystemUIDefaultModule; import com.android.systemui.dagger.SystemUIModule; -import com.android.systemui.dagger.SystemUIRootComponent; import com.android.systemui.onehanded.dagger.OneHandedModule; import javax.inject.Singleton; @@ -42,14 +41,17 @@ import dagger.Component; SystemServicesModule.class, SystemUIBinder.class, SystemUIModule.class, - SystemUIDefaultModule.class, + TvSystemUIModule.class, TvSystemUIBinder.class}) -public interface TvSystemUIRootComponent extends SystemUIRootComponent { +public interface TvGlobalRootComponent extends GlobalRootComponent { /** * Component Builder interface. This allows to bind Context instance in the component */ @Component.Builder - interface Builder extends SystemUIRootComponent.Builder { - TvSystemUIRootComponent build(); + interface Builder extends GlobalRootComponent.Builder { + TvGlobalRootComponent build(); } + + @Override + TvSysUIComponent.Builder getSysUIComponent(); } diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java b/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java new file mode 100644 index 000000000000..bc0cb51c64a3 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2019 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.tv; + +import com.android.systemui.dagger.SysUIComponent; +import com.android.systemui.dagger.SysUISingleton; + +import dagger.Subcomponent; + +/** + * Dagger Subcomponent for Core SysUI. + */ +@SysUISingleton +@Subcomponent(modules = {}) +public interface TvSysUIComponent extends SysUIComponent { + + /** + * Builder for a SysUIComponent. + */ + @Subcomponent.Builder + interface Builder extends SysUIComponent.Builder { + TvSysUIComponent build(); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java index be30a4a4c72e..9a44bf12a3ef 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java +++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java @@ -16,7 +16,7 @@ package com.android.systemui.tv; -import com.android.systemui.dagger.SystemUIRootComponent; +import com.android.systemui.dagger.GlobalRootComponent; import com.android.systemui.pip.tv.dagger.PipModule; import dagger.Binds; @@ -25,5 +25,5 @@ import dagger.Module; @Module(includes = {PipModule.class}) interface TvSystemUIBinder { @Binds - SystemUIRootComponent bindSystemUIRootComponent(TvSystemUIRootComponent systemUIRootComponent); + GlobalRootComponent bindGlobalRootComponent(TvGlobalRootComponent globalRootComponent); } diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIFactory.java index 7d3ec678fd5f..c99ad23ab23d 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIFactory.java +++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIFactory.java @@ -19,16 +19,16 @@ package com.android.systemui.tv; import android.content.Context; import com.android.systemui.SystemUIFactory; -import com.android.systemui.dagger.SystemUIRootComponent; +import com.android.systemui.dagger.GlobalRootComponent; /** - * TV variant {@link SystemUIFactory}, that substitutes default {@link SystemUIRootComponent} for - * {@link TvSystemUIRootComponent} + * TV variant {@link SystemUIFactory}, that substitutes default {@link GlobalRootComponent} for + * {@link TvGlobalRootComponent} */ public class TvSystemUIFactory extends SystemUIFactory { @Override - protected SystemUIRootComponent buildSystemUIRootComponent(Context context) { - return DaggerTvSystemUIRootComponent.builder() + protected GlobalRootComponent buildGlobalRootComponent(Context context) { + return DaggerTvGlobalRootComponent.builder() .context(context) .build(); } diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java new file mode 100644 index 000000000000..0baecd51653f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2019 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.tv; + +import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME; +import static com.android.systemui.Dependency.LEAK_REPORT_EMAIL_NAME; + +import android.content.Context; +import android.os.Handler; +import android.os.PowerManager; + +import androidx.annotation.Nullable; + +import com.android.keyguard.KeyguardViewController; +import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.demomode.DemoModeController; +import com.android.systemui.dock.DockManager; +import com.android.systemui.dock.DockManagerImpl; +import com.android.systemui.doze.DozeHost; +import com.android.systemui.plugins.qs.QSFactory; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.power.EnhancedEstimates; +import com.android.systemui.power.EnhancedEstimatesImpl; +import com.android.systemui.qs.dagger.QSModule; +import com.android.systemui.qs.tileimpl.QSFactoryImpl; +import com.android.systemui.recents.Recents; +import com.android.systemui.recents.RecentsImplementation; +import com.android.systemui.stackdivider.DividerModule; +import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.NotificationLockscreenUserManager; +import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl; +import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.phone.DozeServiceHost; +import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; +import com.android.systemui.statusbar.phone.KeyguardBypassController; +import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl; +import com.android.systemui.statusbar.phone.NotificationGroupManager; +import com.android.systemui.statusbar.phone.ShadeController; +import com.android.systemui.statusbar.phone.ShadeControllerImpl; +import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; +import com.android.systemui.statusbar.policy.BatteryController; +import com.android.systemui.statusbar.policy.BatteryControllerImpl; +import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.DeviceProvisionedController; +import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl; +import com.android.systemui.statusbar.policy.HeadsUpManager; +import com.android.systemui.wmshell.WindowManagerShellModule; + +import javax.inject.Named; +import javax.inject.Singleton; + +import dagger.Binds; +import dagger.Module; +import dagger.Provides; + +/** + * A dagger module for injecting default implementations of components of System UI that may be + * overridden by the System UI implementation. + */ +@Module(includes = { + DividerModule.class, + QSModule.class, + WindowManagerShellModule.class + }, + subcomponents = { + TvSysUIComponent.class + }) +public abstract class TvSystemUIModule { + + @Singleton + @Provides + @Named(LEAK_REPORT_EMAIL_NAME) + @Nullable + static String provideLeakReportEmail() { + return null; + } + + @Binds + abstract EnhancedEstimates bindEnhancedEstimates(EnhancedEstimatesImpl enhancedEstimates); + + @Binds + abstract NotificationLockscreenUserManager bindNotificationLockscreenUserManager( + NotificationLockscreenUserManagerImpl notificationLockscreenUserManager); + + @Provides + @Singleton + static BatteryController provideBatteryController(Context context, + EnhancedEstimates enhancedEstimates, PowerManager powerManager, + BroadcastDispatcher broadcastDispatcher, DemoModeController demoModeController, + @Main Handler mainHandler, @Background Handler bgHandler) { + BatteryController bC = new BatteryControllerImpl(context, enhancedEstimates, powerManager, + broadcastDispatcher, demoModeController, mainHandler, bgHandler); + bC.init(); + return bC; + } + + @Binds + @Singleton + abstract QSFactory bindQSFactory(QSFactoryImpl qsFactoryImpl); + + @Binds + abstract DockManager bindDockManager(DockManagerImpl dockManager); + + @Binds + abstract NotificationEntryManager.KeyguardEnvironment bindKeyguardEnvironment( + KeyguardEnvironmentImpl keyguardEnvironment); + + @Binds + abstract ShadeController provideShadeController(ShadeControllerImpl shadeController); + + @Singleton + @Provides + @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) + static boolean provideAllowNotificationLongPress() { + return true; + } + + @Singleton + @Provides + static HeadsUpManagerPhone provideHeadsUpManagerPhone( + Context context, + StatusBarStateController statusBarStateController, + KeyguardBypassController bypassController, + NotificationGroupManager groupManager, + ConfigurationController configurationController) { + return new HeadsUpManagerPhone(context, statusBarStateController, bypassController, + groupManager, configurationController); + } + + @Binds + abstract HeadsUpManager bindHeadsUpManagerPhone(HeadsUpManagerPhone headsUpManagerPhone); + + @Provides + @Singleton + static Recents provideRecents(Context context, RecentsImplementation recentsImplementation, + CommandQueue commandQueue) { + return new Recents(context, recentsImplementation, commandQueue); + } + + @Binds + abstract DeviceProvisionedController bindDeviceProvisionedController( + DeviceProvisionedControllerImpl deviceProvisionedController); + + @Binds + abstract KeyguardViewController bindKeyguardViewController( + StatusBarKeyguardViewManager statusBarKeyguardViewManager); + + @Binds + abstract DozeHost provideDozeHost(DozeServiceHost dozeServiceHost); +} diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java index d16bedcad960..c82b39af4ab3 100644 --- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java +++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java @@ -23,16 +23,13 @@ import android.view.InflateException; import android.view.LayoutInflater; import android.view.View; -import com.android.keyguard.KeyguardClockSwitch; import com.android.keyguard.KeyguardMessageArea; import com.android.keyguard.KeyguardSliceView; -import com.android.systemui.dagger.SystemUIRootComponent; import com.android.systemui.qs.QSFooterImpl; import com.android.systemui.qs.QSPanel; import com.android.systemui.qs.QuickQSPanel; import com.android.systemui.qs.QuickStatusBarHeader; import com.android.systemui.qs.customize.QSCustomizer; -import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import java.lang.reflect.InvocationTargetException; @@ -43,8 +40,7 @@ import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; -import dagger.Module; -import dagger.Provides; +import dagger.BindsInstance; import dagger.Subcomponent; /** @@ -55,24 +51,16 @@ import dagger.Subcomponent; public class InjectionInflationController { public static final String VIEW_CONTEXT = "view_context"; - private final ViewCreator mViewCreator; private final ArrayMap<String, Method> mInjectionMap = new ArrayMap<>(); private final LayoutInflater.Factory2 mFactory = new InjectionFactory(); + private final ViewInstanceCreator.Factory mViewInstanceCreatorFactory; @Inject - public InjectionInflationController(SystemUIRootComponent rootComponent) { - mViewCreator = rootComponent.createViewCreator(); + public InjectionInflationController(ViewInstanceCreator.Factory viewInstanceCreatorFactory) { + mViewInstanceCreatorFactory = viewInstanceCreatorFactory; initInjectionMap(); } - ArrayMap<String, Method> getInjectionMap() { - return mInjectionMap; - } - - ViewCreator getFragmentCreator() { - return mViewCreator; - } - /** * Wraps a {@link LayoutInflater} to support creating dagger injected views. * See docs/dagger.md for details. @@ -93,25 +81,19 @@ public class InjectionInflationController { } /** - * The subcomponent of dagger that holds all views that need injection. + * Subcomponent that actually creates injected views. */ @Subcomponent - public interface ViewCreator { - /** - * Creates another subcomponent to actually generate the view. - */ - ViewInstanceCreator createInstanceCreator(ViewAttributeProvider attributeProvider); - } - - /** - * Secondary sub-component that actually creates the views. - * - * Having two subcomponents lets us hide the complexity of providing the named context - * and AttributeSet from the SystemUIRootComponent, instead we have one subcomponent that - * creates a new ViewInstanceCreator any time we need to inflate a view. - */ - @Subcomponent(modules = ViewAttributeProvider.class) public interface ViewInstanceCreator { + + /** Factory for creating a ViewInstanceCreator. */ + @Subcomponent.Factory + interface Factory { + ViewInstanceCreator build( + @BindsInstance @Named(VIEW_CONTEXT) Context context, + @BindsInstance AttributeSet attributeSet); + } + /** * Creates the QuickStatusBarHeader. */ @@ -152,36 +134,6 @@ public class InjectionInflationController { QSCustomizer createQSCustomizer(); } - /** - * Module for providing view-specific constructor objects. - */ - @Module - public class ViewAttributeProvider { - private final Context mContext; - private final AttributeSet mAttrs; - - private ViewAttributeProvider(Context context, AttributeSet attrs) { - mContext = context; - mAttrs = attrs; - } - - /** - * Provides the view-themed context (as opposed to the global sysui application context). - */ - @Provides - @Named(VIEW_CONTEXT) - public Context provideContext() { - return mContext; - } - - /** - * Provides the AttributeSet for the current view being inflated. - */ - @Provides - public AttributeSet provideAttributeSet() { - return mAttrs; - } - } private class InjectionFactory implements LayoutInflater.Factory2 { @@ -189,10 +141,9 @@ public class InjectionInflationController { public View onCreateView(String name, Context context, AttributeSet attrs) { Method creationMethod = mInjectionMap.get(name); if (creationMethod != null) { - ViewAttributeProvider provider = new ViewAttributeProvider(context, attrs); try { return (View) creationMethod.invoke( - mViewCreator.createInstanceCreator(provider)); + mViewInstanceCreatorFactory.build(context, attrs)); } catch (IllegalAccessException e) { throw new InflateException("Could not inflate " + name, e); } catch (InvocationTargetException e) { diff --git a/packages/SystemUI/src/com/android/systemui/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java index e5f30cf63ac3..72f1f22c0ba1 100644 --- a/packages/SystemUI/src/com/android/systemui/util/Utils.java +++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java @@ -21,12 +21,15 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.provider.Settings; +import android.text.TextUtils; import android.view.View; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.statusbar.CommandQueue; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.function.Consumer; public class Utils { @@ -143,4 +146,21 @@ public class Utils { Settings.Secure.MEDIA_CONTROLS_RESUME, 1); return useQsMediaPlayer(context) && flag > 0; } + + /** + * Get the set of apps for which the user has manually disabled resumption. + */ + public static Set<String> getBlockedMediaApps(Context context) { + String list = Settings.Secure.getString(context.getContentResolver(), + Settings.Secure.MEDIA_CONTROLS_RESUME_BLOCKED); + if (TextUtils.isEmpty(list)) { + return new HashSet<>(); + } + String[] names = list.split(":"); + Set<String> apps = new HashSet<>(names.length); + for (String s : names) { + apps.add(s); + } + return apps; + } } diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/nullability.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/nullability.kt new file mode 100644 index 000000000000..92c73a412577 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/nullability.kt @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2020 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.util.kotlin + +/** + * If [value] is not null, then returns block(value). Otherwise returns null. + */ +inline fun <T : Any, R> transform(value: T?, block: (T) -> R): R? = value?.let(block) diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeComponent.java index 42393375b45e..e8c5db74f494 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeComponent.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeComponent.java @@ -18,7 +18,7 @@ package com.android.systemui.volume; import android.content.res.Configuration; -import com.android.systemui.DemoMode; +import com.android.systemui.demomode.DemoMode; import java.io.FileDescriptor; import java.io.PrintWriter; diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java index 1c2a2fa53bea..428751bbd73c 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java @@ -27,6 +27,8 @@ import android.view.WindowManager.LayoutParams; import com.android.settingslib.applications.InterestingConfigChanges; import com.android.systemui.Dependency; +import com.android.systemui.demomode.DemoMode; +import com.android.systemui.demomode.DemoModeController; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.PluginDependencyProvider; @@ -38,6 +40,8 @@ import com.android.systemui.tuner.TunerService; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; @@ -72,8 +76,11 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna ); @Inject - public VolumeDialogComponent(Context context, KeyguardViewMediator keyguardViewMediator, - VolumeDialogControllerImpl volumeDialogController) { + public VolumeDialogComponent( + Context context, + KeyguardViewMediator keyguardViewMediator, + VolumeDialogControllerImpl volumeDialogController, + DemoModeController demoModeController) { mContext = context; mKeyguardViewMediator = keyguardViewMediator; mController = volumeDialogController; @@ -94,6 +101,7 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna applyConfiguration(); Dependency.get(TunerService.class).addTunable(this, VOLUME_DOWN_SILENT, VOLUME_UP_SILENT, VOLUME_SILENT_DO_NOT_DISTURB); + demoModeController.addCallback(this); } protected VolumeDialog createDefault() { @@ -164,6 +172,13 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna } @Override + public List<String> demoCommands() { + List<String> s = new ArrayList<>(); + s.add(DemoMode.COMMAND_VOLUME); + return s; + } + + @Override public void register() { mController.register(); DndTile.setCombinedIcon(mContext, true); diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index 4b119dd7e176..51ad30ebcac6 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java @@ -940,6 +940,7 @@ public class VolumeDialogImpl implements VolumeDialog, protected void onStateChangedH(State state) { if (D.BUG) Log.d(TAG, "onStateChangedH() state: " + state.toString()); if (mState != null && state != null + && mState.ringerModeInternal != -1 && mState.ringerModeInternal != state.ringerModeInternal && state.ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE) { mController.vibrate(VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK)); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java index 4c0762e4ea32..0d52e4fefd3e 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java @@ -79,7 +79,9 @@ public class KeyguardClockSwitchTest extends SysuiTestCase { .thenReturn(mMockKeyguardSliceView); InjectionInflationController inflationController = new InjectionInflationController( - SystemUIFactory.getInstance().getRootComponent()); + SystemUIFactory.getInstance() + .getRootComponent() + .createViewInstanceCreatorFactory()); LayoutInflater layoutInflater = inflationController .injectable(LayoutInflater.from(getContext())); layoutInflater.setPrivateFactory(new LayoutInflater.Factory2() { diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java index e6c2ddcf7e65..aa4db3205d82 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java @@ -65,7 +65,9 @@ public class KeyguardPresentationTest extends SysuiTestCase { allowTestableLooperAsMainThread(); InjectionInflationController inflationController = new InjectionInflationController( - SystemUIFactory.getInstance().getRootComponent()); + SystemUIFactory.getInstance() + .getRootComponent() + .createViewInstanceCreatorFactory()); mLayoutInflater = inflationController.injectable(LayoutInflater.from(mContext)); mLayoutInflater.setPrivateFactory(new LayoutInflater.Factory2() { diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java index bc3c3d995ce6..560d581c20e7 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java @@ -51,7 +51,9 @@ public class KeyguardStatusViewTest extends SysuiTestCase { allowTestableLooperAsMainThread(); mDependency.injectMockDependency(KeyguardUpdateMonitor.class); InjectionInflationController inflationController = new InjectionInflationController( - SystemUIFactory.getInstance().getRootComponent()); + SystemUIFactory.getInstance() + .getRootComponent() + .createViewInstanceCreatorFactory()); LayoutInflater layoutInflater = inflationController .injectable(LayoutInflater.from(getContext())); mKeyguardStatusView = diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java index 60f0cd9da5f2..e967a5d607eb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java @@ -82,8 +82,7 @@ public class ForegroundServiceControllerTest extends SysuiTestCase { allowTestableLooperAsMainThread(); MockitoAnnotations.initMocks(this); - mFsc = new ForegroundServiceController( - mEntryManager, mAppOpsController, mMainHandler); + mFsc = new ForegroundServiceController(mAppOpsController, mMainHandler); mListener = new ForegroundServiceNotificationListener( mContext, mFsc, mEntryManager, mNotifPipeline, mock(ForegroundServiceLifetimeExtender.class), mClock); @@ -115,85 +114,6 @@ public class ForegroundServiceControllerTest extends SysuiTestCase { } @Test - public void testAppOps_appOpChangedBeforeNotificationExists() { - // GIVEN app op exists, but notification doesn't exist in NEM yet - NotificationEntry entry = createFgEntry(); - mFsc.onAppOpChanged( - AppOpsManager.OP_CAMERA, - entry.getSbn().getUid(), - entry.getSbn().getPackageName(), - true); - assertFalse(entry.mActiveAppOps.contains(AppOpsManager.OP_CAMERA)); - - // WHEN the notification is added - mEntryListener.onPendingEntryAdded(entry); - - // THEN the app op is added to the entry - Assert.assertTrue(entry.mActiveAppOps.contains(AppOpsManager.OP_CAMERA)); - } - - @Test - public void testAppOps_appOpAddedToForegroundNotif() { - // GIVEN a notification associated with a foreground service - NotificationEntry entry = addFgEntry(); - when(mEntryManager.getPendingOrActiveNotif(entry.getKey())).thenReturn(entry); - - // WHEN we are notified of a new app op for this notification - mFsc.onAppOpChanged( - AppOpsManager.OP_CAMERA, - entry.getSbn().getUid(), - entry.getSbn().getPackageName(), - true); - - // THEN the app op is added to the entry - Assert.assertTrue(entry.mActiveAppOps.contains(AppOpsManager.OP_CAMERA)); - - // THEN notification views are updated since the notification is visible - verify(mEntryManager, times(1)).updateNotifications(anyString()); - } - - @Test - public void testAppOpsAlreadyAdded() { - // GIVEN a foreground service associated notification that already has the correct app op - NotificationEntry entry = addFgEntry(); - entry.mActiveAppOps.add(AppOpsManager.OP_CAMERA); - when(mEntryManager.getPendingOrActiveNotif(entry.getKey())).thenReturn(entry); - - // WHEN we are notified of the same app op for this notification - mFsc.onAppOpChanged( - AppOpsManager.OP_CAMERA, - entry.getSbn().getUid(), - entry.getSbn().getPackageName(), - true); - - // THEN the app op still exists in the notification entry - Assert.assertTrue(entry.mActiveAppOps.contains(AppOpsManager.OP_CAMERA)); - - // THEN notification views aren't updated since nothing changed - verify(mEntryManager, never()).updateNotifications(anyString()); - } - - @Test - public void testAppOps_appOpNotAddedToUnrelatedNotif() { - // GIVEN no notification entries correspond to the newly updated appOp - NotificationEntry entry = addFgEntry(); - when(mEntryManager.getPendingOrActiveNotif(entry.getKey())).thenReturn(null); - - // WHEN a new app op is detected - mFsc.onAppOpChanged( - AppOpsManager.OP_CAMERA, - entry.getSbn().getUid(), - entry.getSbn().getPackageName(), - true); - - // THEN we won't see appOps on the entry - Assert.assertFalse(entry.mActiveAppOps.contains(AppOpsManager.OP_CAMERA)); - - // THEN notification views aren't updated since nothing changed - verify(mEntryManager, never()).updateNotifications(anyString()); - } - - @Test public void testAppOpsCRUD() { // no crash on remove that doesn't exist mFsc.onAppOpChanged(9, 1000, "pkg1", false); diff --git a/packages/SystemUI/tests/src/com/android/systemui/assist/AssistHandleBehaviorControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/assist/AssistHandleBehaviorControllerTest.java index afcd4414c667..7567f0cf04b6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/assist/AssistHandleBehaviorControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/assist/AssistHandleBehaviorControllerTest.java @@ -41,7 +41,7 @@ import com.android.internal.app.AssistUtils; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.systemui.SysuiTestCase; import com.android.systemui.dump.DumpManager; -import com.android.systemui.statusbar.phone.NavigationModeController; +import com.android.systemui.navigationbar.NavigationModeController; import org.junit.After; import org.junit.Before; diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java index 1538a32ecf8a..5c86fcb6b008 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java @@ -211,7 +211,8 @@ public class BubbleControllerTest extends SysuiTestCase { when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors); mSuperStatusBarViewFactory = new SuperStatusBarViewFactory(mContext, - new InjectionInflationController(SystemUIFactory.getInstance().getRootComponent()), + new InjectionInflationController(SystemUIFactory.getInstance().getRootComponent() + .createViewInstanceCreatorFactory()), new NotificationShelfComponent.Builder() { @Override public NotificationShelfComponent.Builder notificationShelf( diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java index 0e7cb79ec266..196aa65bd28f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java @@ -201,7 +201,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors); mSuperStatusBarViewFactory = new SuperStatusBarViewFactory(mContext, - new InjectionInflationController(SystemUIFactory.getInstance().getRootComponent()), + new InjectionInflationController(SystemUIFactory.getInstance().getRootComponent() + .createViewInstanceCreatorFactory()), new NotificationShelfComponent.Builder() { @Override public NotificationShelfComponent.Builder notificationShelf( diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java index f70fb4f55a8d..d1f505baa9e3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java @@ -254,16 +254,12 @@ public class KeyguardSliceProviderTest extends SysuiTestCase { int mCleanDateFormatInvokations; private int mCounter; - Uri getUri() { - return mSliceUri; - } + TestableKeyguardSliceProvider() { + super(); - @Override - protected void inject() { mAlarmManager = KeyguardSliceProviderTest.this.mAlarmManager; mContentResolver = KeyguardSliceProviderTest.this.mContentResolver; mZenModeController = KeyguardSliceProviderTest.this.mZenModeController; - mMediaWakeLock = KeyguardSliceProviderTest.this.mMediaWakeLock; mDozeParameters = KeyguardSliceProviderTest.this.mDozeParameters; mNextAlarmController = KeyguardSliceProviderTest.this.mNextAlarmController; mStatusBarStateController = KeyguardSliceProviderTest.this.mStatusBarStateController; @@ -272,6 +268,17 @@ public class KeyguardSliceProviderTest extends SysuiTestCase { } @Override + public boolean onCreateSliceProvider() { + boolean result = super.onCreateSliceProvider(); + mMediaWakeLock = KeyguardSliceProviderTest.this.mMediaWakeLock; + return result; + } + + Uri getUri() { + return mSliceUri; + } + + @Override protected boolean isDndOn() { return mIsZenMode; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java index 90e9ef4e9c56..c874b1fb72ad 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java @@ -42,10 +42,11 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.dump.DumpManager; -import com.android.systemui.statusbar.phone.NavigationModeController; +import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.DeviceConfigProxyFake; +import com.android.systemui.util.InjectionInflationController; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.time.FakeSystemClock; @@ -71,6 +72,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { private @Mock PowerManager mPowerManager; private @Mock TrustManager mTrustManager; private @Mock NavigationModeController mNavigationModeController; + private @Mock InjectionInflationController mInjectionInflationController; private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake(); private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock()); @@ -88,7 +90,8 @@ public class KeyguardViewMediatorTest extends SysuiTestCase { mContext, mFalsingManager, mLockPatternUtils, mBroadcastDispatcher, () -> mStatusBarKeyguardViewManager, mDismissCallbackRegistry, mUpdateMonitor, mDumpManager, mUiBgExecutor, - mPowerManager, mTrustManager, mDeviceConfig, mNavigationModeController); + mPowerManager, mTrustManager, mDeviceConfig, mNavigationModeController, + mInjectionInflationController); mViewMediator.start(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java index 492b33e3c4a6..2e794a40d238 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java @@ -83,8 +83,8 @@ public class MediaDataCombineLatestTest extends SysuiTestCase { mManager.addListener(mListener); mMediaData = new MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, - new ArrayList<>(), new ArrayList<>(), PACKAGE, null, null, null, true, null, false, - KEY, false); + new ArrayList<>(), new ArrayList<>(), PACKAGE, null, null, null, true, null, true, + false, KEY, false); mDeviceData = new MediaDeviceData(true, null, DEVICE_NAME); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt index a4ebe1ff2a4e..457d559449e1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt @@ -199,6 +199,58 @@ class MediaDataManagerTest : SysuiTestCase() { } @Test + fun testAppBlockedFromResumption() { + // GIVEN that the manager has a notification with a resume action + val listener = TestListener() + mediaDataManager.addListener(listener) + whenever(controller.metadata).thenReturn(metadataBuilder.build()) + mediaDataManager.onNotificationAdded(KEY, mediaNotification) + assertThat(backgroundExecutor.runAllReady()).isEqualTo(1) + assertThat(foregroundExecutor.runAllReady()).isEqualTo(1) + val data = listener.data!! + assertThat(data.resumption).isFalse() + mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {})) + + // and the manager should block the package from creating resume controls + val blocked = mutableSetOf(PACKAGE_NAME, "com.example.app") + mediaDataManager.appsBlockedFromResume = blocked + + // WHEN the notification is removed + mediaDataManager.onNotificationRemoved(KEY) + + // THEN the media data is removed + assertThat(listener.removedKey!!).isEqualTo(KEY) + } + + @Test + fun testAppUnblockedFromResumption() { + // GIVEN that an app was blocked from resuming + val blocked = mutableSetOf(PACKAGE_NAME, "com.example.app") + mediaDataManager.appsBlockedFromResume = blocked + + // and GIVEN that the manager has a notification from that app with a resume action + val listener = TestListener() + mediaDataManager.addListener(listener) + whenever(controller.metadata).thenReturn(metadataBuilder.build()) + mediaDataManager.onNotificationAdded(KEY, mediaNotification) + assertThat(backgroundExecutor.runAllReady()).isEqualTo(1) + assertThat(foregroundExecutor.runAllReady()).isEqualTo(1) + val data = listener.data!! + assertThat(data.resumption).isFalse() + mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {})) + + // WHEN the app is unblocked + mediaDataManager.appsBlockedFromResume = mutableSetOf("com.example.app") + + // and the notification is removed + mediaDataManager.onNotificationRemoved(KEY) + + // THEN the entry will stay as a resume control + assertThat(listener.key!!).isEqualTo(PACKAGE_NAME) + assertThat(listener.oldKey!!).isEqualTo(KEY) + } + + @Test fun testAddResumptionControls() { val listener = TestListener() mediaDataManager.addListener(listener) diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt new file mode 100644 index 000000000000..118cffc2d5b8 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2020 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 + +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito.mock +import org.mockito.Mockito.`when` as whenever + +@SmallTest +@RunWith(AndroidTestingRunner::class) +public class MediaPlayerDataTest : SysuiTestCase() { + + companion object { + val LOCAL = true + val RESUMPTION = true + } + + @Before + fun setup() { + MediaPlayerData.clear() + } + + @Test + fun addPlayingThenRemote() { + val playerIsPlaying = mock(MediaControlPanel::class.java) + whenever(playerIsPlaying.isPlaying).thenReturn(true) + val dataIsPlaying = createMediaData(LOCAL, !RESUMPTION) + + val playerIsRemote = mock(MediaControlPanel::class.java) + whenever(playerIsRemote.isPlaying).thenReturn(false) + val dataIsRemote = createMediaData(!LOCAL, !RESUMPTION) + + MediaPlayerData.addMediaPlayer("1", dataIsPlaying, playerIsPlaying) + MediaPlayerData.addMediaPlayer("2", dataIsRemote, playerIsRemote) + + val players = MediaPlayerData.players() + assertThat(players).hasSize(2) + assertThat(players).containsExactly(playerIsPlaying, playerIsRemote).inOrder() + } + + @Test + fun switchPlayersPlaying() { + val playerIsPlaying1 = mock(MediaControlPanel::class.java) + whenever(playerIsPlaying1.isPlaying).thenReturn(true) + val dataIsPlaying1 = createMediaData(LOCAL, !RESUMPTION) + + val playerIsPlaying2 = mock(MediaControlPanel::class.java) + whenever(playerIsPlaying2.isPlaying).thenReturn(false) + val dataIsPlaying2 = createMediaData(LOCAL, !RESUMPTION) + + MediaPlayerData.addMediaPlayer("1", dataIsPlaying1, playerIsPlaying1) + MediaPlayerData.addMediaPlayer("2", dataIsPlaying2, playerIsPlaying2) + + whenever(playerIsPlaying1.isPlaying).thenReturn(false) + whenever(playerIsPlaying2.isPlaying).thenReturn(true) + + MediaPlayerData.addMediaPlayer("1", dataIsPlaying1, playerIsPlaying1) + MediaPlayerData.addMediaPlayer("2", dataIsPlaying2, playerIsPlaying2) + + val players = MediaPlayerData.players() + assertThat(players).hasSize(2) + assertThat(players).containsExactly(playerIsPlaying2, playerIsPlaying1).inOrder() + } + + @Test + fun fullOrderTest() { + val playerIsPlaying = mock(MediaControlPanel::class.java) + whenever(playerIsPlaying.isPlaying).thenReturn(true) + val dataIsPlaying = createMediaData(LOCAL, !RESUMPTION) + + val playerIsPlayingAndRemote = mock(MediaControlPanel::class.java) + whenever(playerIsPlayingAndRemote.isPlaying).thenReturn(true) + val dataIsPlayingAndRemote = createMediaData(!LOCAL, !RESUMPTION) + + val playerIsStoppedAndLocal = mock(MediaControlPanel::class.java) + whenever(playerIsStoppedAndLocal.isPlaying).thenReturn(false) + val dataIsStoppedAndLocal = createMediaData(LOCAL, !RESUMPTION) + + val playerIsStoppedAndRemote = mock(MediaControlPanel::class.java) + whenever(playerIsStoppedAndLocal.isPlaying).thenReturn(false) + val dataIsStoppedAndRemote = createMediaData(!LOCAL, !RESUMPTION) + + val playerCanResume = mock(MediaControlPanel::class.java) + whenever(playerCanResume.isPlaying).thenReturn(false) + val dataCanResume = createMediaData(LOCAL, RESUMPTION) + + MediaPlayerData.addMediaPlayer("3", dataIsStoppedAndLocal, playerIsStoppedAndLocal) + MediaPlayerData.addMediaPlayer("5", dataIsStoppedAndRemote, playerIsStoppedAndRemote) + MediaPlayerData.addMediaPlayer("4", dataCanResume, playerCanResume) + MediaPlayerData.addMediaPlayer("1", dataIsPlaying, playerIsPlaying) + MediaPlayerData.addMediaPlayer("2", dataIsPlayingAndRemote, playerIsPlayingAndRemote) + + val players = MediaPlayerData.players() + assertThat(players).hasSize(5) + assertThat(players).containsExactly(playerIsPlaying, playerIsPlayingAndRemote, + playerIsStoppedAndLocal, playerCanResume, playerIsStoppedAndRemote).inOrder() + } + + private fun createMediaData(isLocalSession: Boolean, resumption: Boolean) = + MediaData(0, false, 0, null, null, null, null, null, emptyList(), emptyList<Int>(), "", + null, null, null, true, null, isLocalSession, resumption, null, false) +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarButtonTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarButtonTest.java index aae075777506..37b7cbeb8ad6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarButtonTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarButtonTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.phone; +package com.android.systemui.navigationbar; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -35,6 +35,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.SysuiTestableContext; import com.android.systemui.assist.AssistManager; +import com.android.systemui.navigationbar.NavigationBarView; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -65,6 +66,7 @@ public class NavigationBarButtonTest extends SysuiTestCase { mDependency.injectMockDependency(AssistManager.class); mDependency.injectMockDependency(OverviewProxyService.class); mDependency.injectMockDependency(KeyguardStateController.class); + mDependency.injectMockDependency(NavigationBarController.class); mNavBar = new NavigationBarView(context, null); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java index 3c66ac6acd04..2e4d8a7ff472 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar; +package com.android.systemui.navigationbar; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; @@ -36,12 +36,32 @@ import static org.mockito.Mockito.verify; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; import android.util.SparseArray; +import android.view.WindowManager; +import android.view.accessibility.AccessibilityManager; import androidx.test.filters.SmallTest; +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.UiEventLogger; import com.android.systemui.Dependency; import com.android.systemui.SysuiTestCase; -import com.android.systemui.statusbar.phone.NavigationBarFragment; +import com.android.systemui.accessibility.SystemActions; +import com.android.systemui.assist.AssistManager; +import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.model.SysUiState; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.recents.OverviewProxyService; +import com.android.systemui.recents.Recents; +import com.android.systemui.stackdivider.Divider; +import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.NotificationRemoteInputManager; +import com.android.systemui.statusbar.phone.ShadeController; +import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; +import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.DeviceProvisionedController; + +import java.util.Optional; import org.junit.After; import org.junit.Before; @@ -55,27 +75,47 @@ import org.junit.runner.RunWith; public class NavigationBarControllerTest extends SysuiTestCase { private NavigationBarController mNavigationBarController; - private NavigationBarFragment mDefaultNavBar; - private NavigationBarFragment mSecondaryNavBar; + private NavigationBar mDefaultNavBar; + private NavigationBar mSecondaryNavBar; private static final int SECONDARY_DISPLAY = 1; @Before public void setUp() { mNavigationBarController = spy( - new NavigationBarController(mContext, Dependency.get(Dependency.MAIN_HANDLER), - mock(CommandQueue.class))); + new NavigationBarController(mContext, + mock(WindowManager.class), + () -> mock(AssistManager.class), + mock(AccessibilityManager.class), + mock(AccessibilityManagerWrapper.class), + mock(DeviceProvisionedController.class), + mock(MetricsLogger.class), + mock(OverviewProxyService.class), + mock(NavigationModeController.class), + mock(StatusBarStateController.class), + mock(SysUiState.class), + mock(BroadcastDispatcher.class), + mock(CommandQueue.class), + mock(Divider.class), + Optional.of(mock(Recents.class)), + () -> mock(StatusBar.class), + mock(ShadeController.class), + mock(NotificationRemoteInputManager.class), + mock(SystemActions.class), + Dependency.get(Dependency.MAIN_HANDLER), + mock(UiEventLogger.class), + mock(ConfigurationController.class))); initializeNavigationBars(); } private void initializeNavigationBars() { mNavigationBarController.mNavigationBars = mock(SparseArray.class); - mDefaultNavBar = mock(NavigationBarFragment.class); + mDefaultNavBar = mock(NavigationBar.class); mDefaultNavBar.mDisplayId = DEFAULT_DISPLAY; doReturn(mDefaultNavBar) .when(mNavigationBarController.mNavigationBars).get(DEFAULT_DISPLAY); - mSecondaryNavBar = mock(NavigationBarFragment.class); + mSecondaryNavBar = mock(NavigationBar.class); mSecondaryNavBar.mDisplayId = SECONDARY_DISPLAY; doReturn(mSecondaryNavBar) .when(mNavigationBarController.mNavigationBars).get(SECONDARY_DISPLAY); @@ -90,22 +130,22 @@ public class NavigationBarControllerTest extends SysuiTestCase { @Test public void testCreateNavigationBarsIncludeDefaultTrue() { - doNothing().when(mNavigationBarController).createNavigationBar(any(), any()); + doNothing().when(mNavigationBarController).createNavigationBar(any(), any(), any()); mNavigationBarController.createNavigationBars(true, null); verify(mNavigationBarController).createNavigationBar( - argThat(display -> display.getDisplayId() == DEFAULT_DISPLAY), any()); + argThat(display -> display.getDisplayId() == DEFAULT_DISPLAY), any(), any()); } @Test public void testCreateNavigationBarsIncludeDefaultFalse() { - doNothing().when(mNavigationBarController).createNavigationBar(any(), any()); + doNothing().when(mNavigationBarController).createNavigationBar(any(), any(), any()); mNavigationBarController.createNavigationBars(false, null); verify(mNavigationBarController, never()).createNavigationBar( - argThat(display -> display.getDisplayId() == DEFAULT_DISPLAY), any()); + argThat(display -> display.getDisplayId() == DEFAULT_DISPLAY), any(), any()); } // Tests if NPE occurs when call checkNavBarModes() with invalid display. diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarInflaterViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarInflaterViewTest.java index 80e33fbc6acb..7369c82e23ba 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarInflaterViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarInflaterViewTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.phone; +package com.android.systemui.navigationbar; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.doNothing; @@ -32,6 +32,9 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.assist.AssistManager; +import com.android.systemui.navigationbar.buttons.ButtonDispatcher; +import com.android.systemui.navigationbar.NavigationBarInflaterView; +import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.recents.OverviewProxyService; import org.junit.After; @@ -54,6 +57,7 @@ public class NavigationBarInflaterViewTest extends SysuiTestCase { mDependency.injectMockDependency(AssistManager.class); mDependency.injectMockDependency(OverviewProxyService.class); mDependency.injectMockDependency(NavigationModeController.class); + mDependency.injectMockDependency(NavigationBarController.class); mNavBarInflaterView = spy(new NavigationBarInflaterView(mContext, null)); doNothing().when(mNavBarInflaterView).createInflaters(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarRotationContextTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java index f66524114292..51cf5016e8cc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarRotationContextTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarRotationContextTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.phone; +package com.android.systemui.navigationbar; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -30,7 +30,9 @@ import androidx.test.runner.AndroidJUnit4; import com.android.systemui.SysuiTestCase; import com.android.systemui.SysuiTestableContext; -import com.android.systemui.statusbar.policy.KeyButtonDrawable; +import com.android.systemui.navigationbar.buttons.KeyButtonDrawable; +import com.android.systemui.navigationbar.RotationButton; +import com.android.systemui.navigationbar.RotationButtonController; import com.android.systemui.statusbar.policy.RotationLockController; import org.junit.Before; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java index 00cbddc87726..a643c2dc0f19 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java @@ -1,18 +1,20 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2020 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 + * 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. + * 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.statusbar.phone; +package com.android.systemui.navigationbar; import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT; import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN; @@ -21,7 +23,7 @@ import static android.inputmethodservice.InputMethodService.IME_VISIBLE; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS; -import static com.android.systemui.statusbar.phone.NavigationBarFragment.NavBarActionEvent.NAVBAR_ASSIST_LONGPRESS; +import static com.android.systemui.navigationbar.NavigationBar.NavBarActionEvent.NAVBAR_ASSIST_LONGPRESS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -29,42 +31,35 @@ import static org.junit.Assert.assertNotNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.annotation.LayoutRes; -import android.annotation.Nullable; -import android.app.Fragment; -import android.app.FragmentController; -import android.app.FragmentHostCallback; import android.content.BroadcastReceiver; import android.content.Context; import android.content.IntentFilter; import android.hardware.display.DisplayManagerGlobal; -import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.UserHandle; import android.testing.AndroidTestingRunner; -import android.testing.LeakCheck.Tracker; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import android.view.Display; import android.view.DisplayInfo; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; import android.view.WindowManager; -import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener; +import android.view.WindowMetrics; +import android.view.accessibility.AccessibilityManager; import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEventLogger; import com.android.systemui.Dependency; -import com.android.systemui.SysuiBaseFragmentTest; +import com.android.systemui.SysuiTestCase; import com.android.systemui.SysuiTestableContext; import com.android.systemui.accessibility.SystemActions; import com.android.systemui.assist.AssistManager; @@ -76,10 +71,15 @@ import com.android.systemui.recents.Recents; import com.android.systemui.stackdivider.Divider; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationRemoteInputManager; +import com.android.systemui.statusbar.phone.ShadeController; +import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; import com.android.systemui.statusbar.policy.DeviceProvisionedController; +import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.utils.leaks.LeakCheckedTest; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -90,94 +90,62 @@ import java.util.Optional; @RunWith(AndroidTestingRunner.class) @RunWithLooper(setAsMainLooper = true) @SmallTest -public class NavigationBarFragmentTest extends SysuiBaseFragmentTest { +public class NavigationBarTest extends SysuiTestCase { private static final int EXTERNAL_DISPLAY_ID = 2; - private static final int NAV_BAR_VIEW_ID = 43; - private Fragment mFragmentExternalDisplay; - private FragmentController mControllerExternalDisplay; + private NavigationBar mNavigationBar; + private NavigationBar mExternalDisplayNavigationBar; private SysuiTestableContext mSysuiTestableContextExternal; private OverviewProxyService mOverviewProxyService; private CommandQueue mCommandQueue; private SysUiState mMockSysUiState; + private Handler mHandler; @Mock private BroadcastDispatcher mBroadcastDispatcher; @Mock - private Divider mDivider; - @Mock - private Recents mRecents; - @Mock - private SystemActions mSystemActions; - @Mock private UiEventLogger mUiEventLogger; + @Rule + public final LeakCheckedTest.SysuiLeakCheck mLeakCheck = new LeakCheckedTest.SysuiLeakCheck(); private AccessibilityManagerWrapper mAccessibilityWrapper = - new AccessibilityManagerWrapper(mContext) { - Tracker mTracker = mLeakCheck.getTracker("accessibility_manager"); - - @Override - public void addCallback(AccessibilityServicesStateChangeListener listener) { - mTracker.getLeakInfo(listener).addAllocation(new Throwable()); - } - - @Override - public void removeCallback(AccessibilityServicesStateChangeListener listener) { - mTracker.getLeakInfo(listener).clearAllocations(); - } - }; - - public NavigationBarFragmentTest() { - super(NavigationBarFragment.class); - } - - protected void createRootView() { - mView = new NavigationBarFrame(mSysuiContext); - mView.setId(NAV_BAR_VIEW_ID); - } + new AccessibilityManagerWrapper(mContext); @Before - public void setupFragment() throws Exception { + public void setup() throws Exception { MockitoAnnotations.initMocks(this); mCommandQueue = new CommandQueue(mContext); setupSysuiDependency(); - createRootView(); - mOverviewProxyService = - mDependency.injectMockDependency(OverviewProxyService.class); + mDependency.injectMockDependency(AssistManager.class); + mDependency.injectMockDependency(KeyguardStateController.class); + mDependency.injectMockDependency(StatusBarStateController.class); + mDependency.injectMockDependency(NavigationBarController.class); + mDependency.injectMockDependency(Divider.class); + mOverviewProxyService = mDependency.injectMockDependency(OverviewProxyService.class); TestableLooper.get(this).runWithLooper(() -> { mHandler = new Handler(); - - mFragment = instantiate(mSysuiContext, NavigationBarFragment.class.getName(), null); - mFragments = FragmentController.createController( - new HostCallbacksForExternalDisplay(mSysuiContext)); - mFragments.attachHost(null); - mFragments.getFragmentManager().beginTransaction() - .replace(NAV_BAR_VIEW_ID, mFragment) - .commit(); - mControllerExternalDisplay = FragmentController.createController( - new HostCallbacksForExternalDisplay(mSysuiTestableContextExternal)); - mControllerExternalDisplay.attachHost(null); - mFragmentExternalDisplay = instantiate(mSysuiTestableContextExternal, - NavigationBarFragment.class.getName(), null); - mControllerExternalDisplay.getFragmentManager().beginTransaction() - .replace(NAV_BAR_VIEW_ID, mFragmentExternalDisplay) - .commit(); + mNavigationBar = createNavBar(mContext); + mExternalDisplayNavigationBar = createNavBar(mSysuiTestableContextExternal); }); } private void setupSysuiDependency() { Display display = new Display(DisplayManagerGlobal.getInstance(), EXTERNAL_DISPLAY_ID, new DisplayInfo(), DEFAULT_DISPLAY_ADJUSTMENTS); - mSysuiTestableContextExternal = (SysuiTestableContext) mSysuiContext.createDisplayContext( + mSysuiTestableContextExternal = (SysuiTestableContext) getContext().createDisplayContext( display); - injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES); WindowManager windowManager = mock(WindowManager.class); Display defaultDisplay = mContext.getSystemService(WindowManager.class).getDefaultDisplay(); when(windowManager.getDefaultDisplay()).thenReturn( defaultDisplay); + WindowMetrics metrics = mContext.getSystemService(WindowManager.class) + .getMaximumWindowMetrics(); + when(windowManager.getMaximumWindowMetrics()).thenReturn(metrics); + doNothing().when(windowManager).addView(any(), any()); mContext.addMockSystemService(Context.WINDOW_SERVICE, windowManager); + mSysuiTestableContextExternal.addMockSystemService(Context.WINDOW_SERVICE, windowManager); mDependency.injectTestDependency(Dependency.BG_LOOPER, Looper.getMainLooper()); mDependency.injectTestDependency(AccessibilityManagerWrapper.class, mAccessibilityWrapper); @@ -188,20 +156,15 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest { @Test public void testHomeLongPress() { - NavigationBarFragment navigationBarFragment = (NavigationBarFragment) mFragment; - - mFragments.dispatchResume(); - processAllMessages(); - navigationBarFragment.onHomeLongClick(navigationBarFragment.getView()); + mNavigationBar.onViewAttachedToWindow(mNavigationBar.createView(null)); + mNavigationBar.onHomeLongClick(mNavigationBar.getView()); verify(mUiEventLogger, times(1)).log(NAVBAR_ASSIST_LONGPRESS); } @Test public void testRegisteredWithDispatcher() { - mFragments.dispatchResume(); - processAllMessages(); - + mNavigationBar.onViewAttachedToWindow(mNavigationBar.createView(null)); verify(mBroadcastDispatcher).registerReceiverWithHandler( any(BroadcastReceiver.class), any(IntentFilter.class), @@ -212,16 +175,12 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest { @Test public void testSetImeWindowStatusWhenImeSwitchOnDisplay() { // Create default & external NavBar fragment. - NavigationBarFragment defaultNavBar = (NavigationBarFragment) mFragment; - NavigationBarFragment externalNavBar = (NavigationBarFragment) mFragmentExternalDisplay; - mFragments.dispatchCreate(); - processAllMessages(); - mFragments.dispatchResume(); - processAllMessages(); - mControllerExternalDisplay.dispatchCreate(); - processAllMessages(); - mControllerExternalDisplay.dispatchResume(); - processAllMessages(); + NavigationBar defaultNavBar = mNavigationBar; + NavigationBar externalNavBar = mExternalDisplayNavigationBar; + doNothing().when(defaultNavBar).checkNavBarModes(); + doNothing().when(externalNavBar).checkNavBarModes(); + defaultNavBar.createView(null); + externalNavBar.createView(null); // Set IME window status for default NavBar. mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, null, IME_VISIBLE, @@ -246,91 +205,36 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest { assertFalse((defaultNavBar.getNavigationIconHints() & NAVIGATION_HINT_IME_SHOWN) != 0); } - @Override - protected Fragment instantiate(Context context, String className, Bundle arguments) { + private NavigationBar createNavBar(Context context) { DeviceProvisionedController deviceProvisionedController = mock(DeviceProvisionedController.class); when(deviceProvisionedController.isDeviceProvisioned()).thenReturn(true); assertNotNull(mAccessibilityWrapper); - return new NavigationBarFragment( + return spy(new NavigationBar(context, + mock(WindowManager.class), + () -> mock(AssistManager.class), + mock(AccessibilityManager.class), context.getDisplayId() == DEFAULT_DISPLAY ? mAccessibilityWrapper : mock(AccessibilityManagerWrapper.class), deviceProvisionedController, new MetricsLogger(), - mock(AssistManager.class), mOverviewProxyService, mock(NavigationModeController.class), mock(StatusBarStateController.class), mMockSysUiState, mBroadcastDispatcher, mCommandQueue, - mDivider, - Optional.of(mRecents), + mock(Divider.class), + Optional.of(mock(Recents.class)), () -> mock(StatusBar.class), mock(ShadeController.class), mock(NotificationRemoteInputManager.class), mock(SystemActions.class), mHandler, - mUiEventLogger); + mUiEventLogger)); } - private class HostCallbacksForExternalDisplay extends - FragmentHostCallback<NavigationBarFragmentTest> { - private Context mDisplayContext; - - HostCallbacksForExternalDisplay(Context context) { - super(context, mHandler, 0); - mDisplayContext = context; - } - - @Override - public NavigationBarFragmentTest onGetHost() { - return NavigationBarFragmentTest.this; - } - - @Override - public Fragment instantiate(Context context, String className, Bundle arguments) { - return NavigationBarFragmentTest.this.instantiate(context, className, arguments); - } - - @Override - public View onFindViewById(int id) { - return mView.findViewById(id); - } - - @Override - public LayoutInflater onGetLayoutInflater() { - return new LayoutInflaterWrapper(mDisplayContext); - } - } - - private static class LayoutInflaterWrapper extends LayoutInflater { - protected LayoutInflaterWrapper(Context context) { - super(context); - } - - @Override - public LayoutInflater cloneInContext(Context newContext) { - return null; - } - - @Override - public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, - boolean attachToRoot) { - NavigationBarView view = mock(NavigationBarView.class); - when(view.getDisplay()).thenReturn(mContext.getDisplay()); - when(view.getBackButton()).thenReturn(mock(ButtonDispatcher.class)); - when(view.getHomeButton()).thenReturn(mock(ButtonDispatcher.class)); - when(view.getRecentsButton()).thenReturn(mock(ButtonDispatcher.class)); - when(view.getAccessibilityButton()).thenReturn(mock(ButtonDispatcher.class)); - when(view.getRotateSuggestionButton()).thenReturn(mock(RotationContextButton.class)); - when(view.getBarTransitions()).thenReturn(mock(NavigationBarTransitions.class)); - when(view.getLightTransitionsController()).thenReturn( - mock(LightBarTransitionsController.class)); - when(view.getRotationButtonController()).thenReturn( - mock(RotationButtonController.class)); - when(view.isRecentsButtonVisible()).thenReturn(true); - return view; - } + private void processAllMessages() { + TestableLooper.get(this).processAllMessages(); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarTransitionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java index 14c6e9f9624d..7e0920cc998d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarTransitionsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java @@ -1,18 +1,20 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2020 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 + * 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. + * 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.statusbar.phone; +package com.android.systemui.navigationbar; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -30,9 +32,13 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.assist.AssistManager; +import com.android.systemui.navigationbar.NavigationBarTransitions; +import com.android.systemui.navigationbar.NavigationBarView; +import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.phone.BarTransitions; import com.android.systemui.statusbar.policy.KeyguardStateController; import org.junit.Before; @@ -53,6 +59,7 @@ public class NavigationBarTransitionsTest extends SysuiTestCase { mDependency.injectMockDependency(OverviewProxyService.class); mDependency.injectMockDependency(StatusBarStateController.class); mDependency.injectMockDependency(KeyguardStateController.class); + mDependency.injectMockDependency(NavigationBarController.class); doReturn(mContext) .when(mDependency.injectMockDependency(NavigationModeController.class)) .getCurrentUserContext(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyButtonViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/KeyButtonViewTest.java index d52d6860bf42..3f10c8da576b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyButtonViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/KeyButtonViewTest.java @@ -1,18 +1,20 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2020 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 + * 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. + * 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.statusbar.policy; +package com.android.systemui.navigationbar.buttons; import static android.view.KeyEvent.ACTION_DOWN; import static android.view.KeyEvent.ACTION_UP; @@ -23,12 +25,12 @@ import static android.view.KeyEvent.KEYCODE_APP_SWITCH; import static android.view.KeyEvent.KEYCODE_BACK; import static android.view.KeyEvent.KEYCODE_HOME; -import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarButtonEvent.NAVBAR_BACK_BUTTON_LONGPRESS; -import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarButtonEvent.NAVBAR_BACK_BUTTON_TAP; -import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarButtonEvent.NAVBAR_HOME_BUTTON_LONGPRESS; -import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarButtonEvent.NAVBAR_HOME_BUTTON_TAP; -import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarButtonEvent.NAVBAR_OVERVIEW_BUTTON_LONGPRESS; -import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarButtonEvent.NAVBAR_OVERVIEW_BUTTON_TAP; +import static com.android.systemui.navigationbar.buttons.KeyButtonView.NavBarButtonEvent.NAVBAR_BACK_BUTTON_LONGPRESS; +import static com.android.systemui.navigationbar.buttons.KeyButtonView.NavBarButtonEvent.NAVBAR_BACK_BUTTON_TAP; +import static com.android.systemui.navigationbar.buttons.KeyButtonView.NavBarButtonEvent.NAVBAR_HOME_BUTTON_LONGPRESS; +import static com.android.systemui.navigationbar.buttons.KeyButtonView.NavBarButtonEvent.NAVBAR_HOME_BUTTON_TAP; +import static com.android.systemui.navigationbar.buttons.KeyButtonView.NavBarButtonEvent.NAVBAR_OVERVIEW_BUTTON_LONGPRESS; +import static com.android.systemui.navigationbar.buttons.KeyButtonView.NavBarButtonEvent.NAVBAR_OVERVIEW_BUTTON_TAP; import static junit.framework.Assert.assertEquals; @@ -52,6 +54,7 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEventLogger; import com.android.systemui.SysuiTestCase; import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.navigationbar.buttons.KeyButtonView; import com.android.systemui.recents.OverviewProxyService; import org.junit.Before; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NavigationBarContextTest.java index 1fb28f0878bd..d56aa777706b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NavigationBarContextTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2020 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. @@ -11,10 +11,10 @@ * 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 + * limitations under the License. */ -package com.android.systemui.statusbar.phone; +package com.android.systemui.navigationbar.buttons; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -35,7 +35,9 @@ import androidx.test.runner.AndroidJUnit4; import com.android.systemui.SysuiTestCase; import com.android.systemui.assist.AssistManager; -import com.android.systemui.statusbar.policy.KeyButtonDrawable; +import com.android.systemui.navigationbar.buttons.ContextualButton; +import com.android.systemui.navigationbar.buttons.ContextualButtonGroup; +import com.android.systemui.navigationbar.buttons.KeyButtonDrawable; import org.junit.Before; import org.junit.Ignore; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NearestTouchFrameTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NearestTouchFrameTest.java index a04bcc0b29c5..0320103ceaa8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NearestTouchFrameTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/NearestTouchFrameTest.java @@ -1,18 +1,20 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2020 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 + * 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. + * 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.statusbar.phone; +package com.android.systemui.navigationbar.buttons; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -31,6 +33,7 @@ import android.view.View; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.navigationbar.buttons.NearestTouchFrame; import org.junit.Before; import org.junit.Test; diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java index f4c07004f632..95a230f6511c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java @@ -31,7 +31,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.model.SysUiState; import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.phone.NavigationModeController; +import com.android.systemui.navigationbar.NavigationModeController; import com.android.wm.shell.common.DisplayController; import org.junit.Before; @@ -79,7 +79,7 @@ public class OneHandedGestureHandlerTest extends OneHandedTestCase { @Test public void testOneHandedManager_registerForDisplayAreaOrganizer() { - verify(mMockDisplayAreaOrganizer, times(1)).registerTransitionCallback(mGestureHandler); + verify(mMockDisplayAreaOrganizer).registerTransitionCallback(mGestureHandler); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedSettingsUtilTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedSettingsUtilTest.java index f81d047b0f0c..990eb634e46f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedSettingsUtilTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedSettingsUtilTest.java @@ -40,14 +40,12 @@ import org.junit.runner.RunWith; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class OneHandedSettingsUtilTest extends OneHandedTestCase { - OneHandedSettingsUtil mOneHandedSettingsUtil; ContentResolver mContentResolver; ContentObserver mContentObserver; boolean mOnChanged; @Before public void setUp() { - mOneHandedSettingsUtil = new OneHandedSettingsUtil(); mContentResolver = mContext.getContentResolver(); mContentObserver = new ContentObserver(mContext.getMainThreadHandler()) { @Override @@ -60,20 +58,20 @@ public class OneHandedSettingsUtilTest extends OneHandedTestCase { @Test public void testRegisterSecureKeyObserver() { - final Uri result = mOneHandedSettingsUtil.registerSettingsKeyObserver( + final Uri result = OneHandedSettingsUtil.registerSettingsKeyObserver( Settings.Secure.ONE_HANDED_MODE_ENABLED, mContentResolver, mContentObserver); assertThat(result).isNotNull(); - mOneHandedSettingsUtil.registerSettingsKeyObserver( + OneHandedSettingsUtil.registerSettingsKeyObserver( Settings.Secure.ONE_HANDED_MODE_ENABLED, mContentResolver, mContentObserver); } @Test public void testUnregisterSecureKeyObserver() { - mOneHandedSettingsUtil.registerSettingsKeyObserver( + OneHandedSettingsUtil.registerSettingsKeyObserver( Settings.Secure.ONE_HANDED_MODE_ENABLED, mContentResolver, mContentObserver); - mOneHandedSettingsUtil.unregisterSettingsKeyObserver(mContentResolver, mContentObserver); + OneHandedSettingsUtil.unregisterSettingsKeyObserver(mContentResolver, mContentObserver); assertThat(mOnChanged).isFalse(); @@ -85,19 +83,19 @@ public class OneHandedSettingsUtilTest extends OneHandedTestCase { @Test public void testGetSettingsIsOneHandedModeEnabled() { - assertThat(mOneHandedSettingsUtil.getSettingsOneHandedModeEnabled( + assertThat(OneHandedSettingsUtil.getSettingsOneHandedModeEnabled( mContentResolver)).isAnyOf(true, false); } @Test public void testGetSettingsTapsAppToExit() { - assertThat(mOneHandedSettingsUtil.getSettingsTapsAppToExit( + assertThat(OneHandedSettingsUtil.getSettingsTapsAppToExit( mContentResolver)).isAnyOf(true, false); } @Test public void testGetSettingsOneHandedModeTimeout() { - assertThat(mOneHandedSettingsUtil.getSettingsOneHandedModeTimeout( + assertThat(OneHandedSettingsUtil.getSettingsOneHandedModeTimeout( mContentResolver)).isAnyOf( ONE_HANDED_TIMEOUT_NEVER, ONE_HANDED_TIMEOUT_SHORT_IN_SECONDS, @@ -107,7 +105,7 @@ public class OneHandedSettingsUtilTest extends OneHandedTestCase { @Test public void testGetSettingsSwipeToNotificationEnabled() { - assertThat(mOneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled( + assertThat(OneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled( mContentResolver)).isAnyOf(true, false); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java index 15881a2e7c18..8ae632dd5a47 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java @@ -29,7 +29,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.model.SysUiState; import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.phone.NavigationModeController; +import com.android.systemui.navigationbar.NavigationModeController; import com.android.wm.shell.common.DisplayController; import org.junit.Before; @@ -77,8 +77,7 @@ public class OneHandedTouchHandlerTest extends OneHandedTestCase { @Test public void testOneHandedManager_registerForDisplayAreaOrganizer() { - verify(mMockDisplayAreaOrganizer, times(1)) - .registerTransitionCallback(mTouchHandler); + verify(mMockDisplayAreaOrganizer).registerTransitionCallback(mTouchHandler); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java index f2b77a0a936b..c75a8d2f5454 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java @@ -16,7 +16,6 @@ package com.android.systemui.onehanded; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.testing.AndroidTestingRunner; @@ -26,7 +25,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.model.SysUiState; import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.phone.NavigationModeController; +import com.android.systemui.navigationbar.NavigationModeController; import com.android.wm.shell.common.DisplayController; import org.junit.Before; @@ -75,7 +74,6 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase { @Test public void testOneHandedManager_registerForDisplayAreaOrganizer() { - verify(mMockDisplayAreaOrganizer, times(1)) - .registerTransitionCallback(mTutorialHandler); + verify(mMockDisplayAreaOrganizer).registerTransitionCallback(mTutorialHandler); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedUITest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedUITest.java index 6db2679ea116..f0e713e42046 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedUITest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedUITest.java @@ -16,8 +16,7 @@ package com.android.systemui.onehanded; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.times; +import static org.junit.Assume.assumeTrue; import static org.mockito.Mockito.verify; import android.os.SystemProperties; @@ -44,7 +43,6 @@ import org.mockito.MockitoAnnotations; public class OneHandedUITest extends OneHandedTestCase { private static final String SUPPORT_ONE_HANDED_MODE = "ro.support_one_handed_mode"; - boolean mIsSupportOneHandedMode; CommandQueue mCommandQueue; KeyguardUpdateMonitor mKeyguardUpdateMonitor; OneHandedUI mOneHandedUI; @@ -52,110 +50,58 @@ public class OneHandedUITest extends OneHandedTestCase { @Mock OneHandedManagerImpl mMockOneHandedManagerImpl; @Mock - OneHandedSettingsUtil mMockSettingsUtil; - @Mock OneHandedTimeoutHandler mMockTimeoutHandler; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mIsSupportOneHandedMode = SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false); mCommandQueue = new CommandQueue(mContext); mScreenLifecycle = new ScreenLifecycle(); mOneHandedUI = new OneHandedUI(mContext, mCommandQueue, mMockOneHandedManagerImpl, - mMockSettingsUtil, mScreenLifecycle); mOneHandedUI.start(); mKeyguardUpdateMonitor = mDependency.injectMockDependency(KeyguardUpdateMonitor.class); } + @Before + public void assumeOneHandedModeSupported() { + assumeTrue(SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false)); + } + @Test public void testStartOneHanded() { - // Bypass test if device not support one-handed mode - if (!mIsSupportOneHandedMode) { - return; - } mOneHandedUI.startOneHanded(); - verify(mMockOneHandedManagerImpl, times(1)).startOneHanded(); + verify(mMockOneHandedManagerImpl).startOneHanded(); } @Test public void testStopOneHanded() { - // Bypass test if device not support one-handed mode - if (!mIsSupportOneHandedMode) { - return; - } mOneHandedUI.stopOneHanded(); - verify(mMockOneHandedManagerImpl, times(1)).stopOneHanded(); - } - - @Test - public void testRegisterSettingsObserver_forEnabled() { - // Bypass test if device not support one-handed mode - if (!mIsSupportOneHandedMode) { - return; - } - final String key = Settings.Secure.ONE_HANDED_MODE_ENABLED; - - verify(mMockSettingsUtil, times(1)).registerSettingsKeyObserver(key, any(), any()); - } - - @Test - public void testRegisterSettingsObserver_forTimeout() { - // Bypass test if device not support one-handed mode - if (!mIsSupportOneHandedMode) { - return; - } - final String key = Settings.Secure.ONE_HANDED_MODE_TIMEOUT; - - verify(mMockSettingsUtil, times(1)).registerSettingsKeyObserver(key, any(), any()); - } - - @Test - public void testRegisterSettingsObserver_forTapAppExit() { - // Bypass test if device not support one-handed mode - if (!mIsSupportOneHandedMode) { - return; - } - final String key = Settings.Secure.TAPS_APP_TO_EXIT; - - verify(mMockSettingsUtil, times(1)).registerSettingsKeyObserver(key, any(), any()); + verify(mMockOneHandedManagerImpl).stopOneHanded(); } @Test public void tesSettingsObserver_updateTapAppToExit() { - // Bypass test if device not support one-handed mode - if (!mIsSupportOneHandedMode) { - return; - } Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.TAPS_APP_TO_EXIT, 1); - verify(mMockOneHandedManagerImpl, times(1)).setTaskChangeToExit(true); + verify(mMockOneHandedManagerImpl).setTaskChangeToExit(true); } @Test public void tesSettingsObserver_updateEnabled() { - // Bypass test if device not support one-handed mode - if (!mIsSupportOneHandedMode) { - return; - } Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.ONE_HANDED_MODE_ENABLED, 1); - verify(mMockOneHandedManagerImpl, times(1)).setOneHandedEnabled(true); + verify(mMockOneHandedManagerImpl).setOneHandedEnabled(true); } @Test public void tesSettingsObserver_updateTimeout() { - // Bypass test if device not support one-handed mode - if (!mIsSupportOneHandedMode) { - return; - } Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.ONE_HANDED_MODE_TIMEOUT, OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS); @@ -166,10 +112,6 @@ public class OneHandedUITest extends OneHandedTestCase { @Test public void tesSettingsObserver_updateSwipeToNotification() { - // Bypass test if device not support one-handed mode - if (!mIsSupportOneHandedMode) { - return; - } Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, 1); @@ -179,24 +121,16 @@ public class OneHandedUITest extends OneHandedTestCase { @Ignore("Clarifying do not receive callback") @Test public void testKeyguardBouncerShowing_shouldStopOneHanded() { - // Bypass test if device not support one-handed mode - if (!mIsSupportOneHandedMode) { - return; - } mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(true); - verify(mMockOneHandedManagerImpl, times(1)).stopOneHanded(); + verify(mMockOneHandedManagerImpl).stopOneHanded(); } @Test public void testScreenTurningOff_shouldStopOneHanded() { - // Bypass test if device not support one-handed mode - if (!mIsSupportOneHandedMode) { - return; - } mScreenLifecycle.dispatchScreenTurningOff(); - verify(mMockOneHandedManagerImpl, times(1)).stopOneHanded(); + verify(mMockOneHandedManagerImpl).stopOneHanded(); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java index d338cbf51fb5..9922d3620a57 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java @@ -150,7 +150,10 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { return new QSFragment( new RemoteInputQuickSettingsDisabler(context, mock(ConfigurationController.class), commandQueue), - new InjectionInflationController(SystemUIFactory.getInstance().getRootComponent()), + new InjectionInflationController( + SystemUIFactory.getInstance() + .getRootComponent() + .createViewInstanceCreatorFactory()), mock(QSTileHost.class), mock(StatusBarStateController.class), commandQueue, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java index 6f46923cda5e..c35ada7c3501 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java @@ -212,19 +212,6 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { } @Test - public void testUpdateNotificationViews_appOps() throws Exception { - NotificationEntry entry0 = createEntry(); - entry0.setRow(spy(entry0.getRow())); - when(mEntryManager.getVisibleNotifications()).thenReturn( - Lists.newArrayList(entry0)); - mListContainer.addContainerView(entry0.getRow()); - - mViewHierarchyManager.updateNotificationViews(); - - verify(entry0.getRow(), times(1)).showAppOpsIcons(any()); - } - - @Test public void testReentrantCallsToOnDynamicPrivacyChangedPostForLater() { // GIVEN a ListContainer that will make a re-entrant call to updateNotificationViews() mMadeReentrantCall = false; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java index 960ea79f36b4..ce8ce2e39bcc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/AppOpsCoordinatorTest.java @@ -77,8 +77,6 @@ public class AppOpsCoordinatorTest extends SysuiTestCase { private NotificationEntryBuilder mEntryBuilder; private AppOpsCoordinator mAppOpsCoordinator; private NotifFilter mForegroundFilter; - private NotifCollectionListener mNotifCollectionListener; - private AppOpsController.Callback mAppOpsCallback; private NotifLifetimeExtender mForegroundNotifLifetimeExtender; private NotifSection mFgsSection; @@ -113,19 +111,6 @@ public class AppOpsCoordinatorTest extends SysuiTestCase { lifetimeExtenderCaptor.capture()); mForegroundNotifLifetimeExtender = lifetimeExtenderCaptor.getValue(); - // capture notifCollectionListener - ArgumentCaptor<NotifCollectionListener> notifCollectionCaptor = - ArgumentCaptor.forClass(NotifCollectionListener.class); - verify(mNotifPipeline, times(1)).addCollectionListener( - notifCollectionCaptor.capture()); - mNotifCollectionListener = notifCollectionCaptor.getValue(); - - // capture app ops callback - ArgumentCaptor<AppOpsController.Callback> appOpsCaptor = - ArgumentCaptor.forClass(AppOpsController.Callback.class); - verify(mAppOpsController).addCallback(any(int[].class), appOpsCaptor.capture()); - mAppOpsCallback = appOpsCaptor.getValue(); - mFgsSection = mAppOpsCoordinator.getSection(); } @@ -230,136 +215,6 @@ public class AppOpsCoordinatorTest extends SysuiTestCase { } @Test - public void testAppOpsUpdateOnlyAppliedToRelevantNotificationWithStandardLayout() { - // GIVEN three current notifications, two with the same key but from different users - NotificationEntry entry1 = new NotificationEntryBuilder() - .setUser(new UserHandle(NOTIF_USER_ID)) - .setPkg(TEST_PKG) - .setId(1) - .build(); - NotificationEntry entry2 = new NotificationEntryBuilder() - .setUser(new UserHandle(NOTIF_USER_ID)) - .setPkg(TEST_PKG) - .setId(2) - .build(); - NotificationEntry entry3_diffUser = new NotificationEntryBuilder() - .setUser(new UserHandle(NOTIF_USER_ID + 1)) - .setPkg(TEST_PKG) - .setId(2) - .build(); - when(mNotifPipeline.getAllNotifs()).thenReturn(List.of(entry1, entry2, entry3_diffUser)); - - // GIVEN that only entry2 has a standard layout - when(mForegroundServiceController.getStandardLayoutKeys(NOTIF_USER_ID, TEST_PKG)) - .thenReturn(new ArraySet<>(List.of(entry2.getKey()))); - - // WHEN a new app ops code comes in - mAppOpsCallback.onActiveStateChanged(47, NOTIF_USER_ID, TEST_PKG, true); - mExecutor.runAllReady(); - - // THEN entry2's app ops are updated, but no one else's are - assertEquals( - new ArraySet<>(), - entry1.mActiveAppOps); - assertEquals( - new ArraySet<>(List.of(47)), - entry2.mActiveAppOps); - assertEquals( - new ArraySet<>(), - entry3_diffUser.mActiveAppOps); - } - - @Test - public void testAppOpsUpdateAppliedToAllNotificationsWithStandardLayouts() { - // GIVEN three notifications with standard layouts - NotificationEntry entry1 = new NotificationEntryBuilder() - .setUser(new UserHandle(NOTIF_USER_ID)) - .setPkg(TEST_PKG) - .setId(1) - .build(); - NotificationEntry entry2 = new NotificationEntryBuilder() - .setUser(new UserHandle(NOTIF_USER_ID)) - .setPkg(TEST_PKG) - .setId(2) - .build(); - NotificationEntry entry3 = new NotificationEntryBuilder() - .setUser(new UserHandle(NOTIF_USER_ID)) - .setPkg(TEST_PKG) - .setId(3) - .build(); - when(mNotifPipeline.getAllNotifs()).thenReturn(List.of(entry1, entry2, entry3)); - when(mForegroundServiceController.getStandardLayoutKeys(NOTIF_USER_ID, TEST_PKG)) - .thenReturn(new ArraySet<>(List.of(entry1.getKey(), entry2.getKey(), - entry3.getKey()))); - - // WHEN a new app ops code comes in - mAppOpsCallback.onActiveStateChanged(47, NOTIF_USER_ID, TEST_PKG, true); - mExecutor.runAllReady(); - - // THEN all entries get updated - assertEquals( - new ArraySet<>(List.of(47)), - entry1.mActiveAppOps); - assertEquals( - new ArraySet<>(List.of(47)), - entry2.mActiveAppOps); - assertEquals( - new ArraySet<>(List.of(47)), - entry3.mActiveAppOps); - } - - @Test - public void testAppOpsAreRemoved() { - // GIVEN One notification which is associated with app ops - NotificationEntry entry = new NotificationEntryBuilder() - .setUser(new UserHandle(NOTIF_USER_ID)) - .setPkg(TEST_PKG) - .setId(2) - .build(); - when(mNotifPipeline.getAllNotifs()).thenReturn(List.of(entry)); - when(mForegroundServiceController.getStandardLayoutKeys(0, TEST_PKG)) - .thenReturn(new ArraySet<>(List.of(entry.getKey()))); - - // GIVEN that the notification's app ops are already [47, 33] - mAppOpsCallback.onActiveStateChanged(47, NOTIF_USER_ID, TEST_PKG, true); - mAppOpsCallback.onActiveStateChanged(33, NOTIF_USER_ID, TEST_PKG, true); - mExecutor.runAllReady(); - assertEquals( - new ArraySet<>(List.of(47, 33)), - entry.mActiveAppOps); - - // WHEN one of the app ops is removed - mAppOpsCallback.onActiveStateChanged(47, NOTIF_USER_ID, TEST_PKG, false); - mExecutor.runAllReady(); - - // THEN the entry's active app ops are updated as well - assertEquals( - new ArraySet<>(List.of(33)), - entry.mActiveAppOps); - } - - @Test - public void testNullAppOps() { - // GIVEN one notification with app ops - NotificationEntry entry = new NotificationEntryBuilder() - .setUser(new UserHandle(NOTIF_USER_ID)) - .setPkg(TEST_PKG) - .setId(2) - .build(); - entry.mActiveAppOps.clear(); - entry.mActiveAppOps.addAll(List.of(47, 33)); - - // WHEN the notification is updated and the foreground service controller returns null for - // this notification - when(mForegroundServiceController.getAppOps(entry.getSbn().getUser().getIdentifier(), - entry.getSbn().getPackageName())).thenReturn(null); - mNotifCollectionListener.onEntryUpdated(entry); - - // THEN the entry's active app ops is updated to empty - assertTrue(entry.mActiveAppOps.isEmpty()); - } - - @Test public void testIncludeFGSInSection_importanceDefault() { // GIVEN the notification represents a colorized foreground service with > min importance mEntryBuilder diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferTest.java new file mode 100644 index 000000000000..bbe92f67ca2e --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferTest.java @@ -0,0 +1,304 @@ +/* + * Copyright (C) 2020 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.statusbar.notification.collection.render; + +import static org.junit.Assert.assertEquals; + +import android.content.Context; +import android.testing.AndroidTestingRunner; +import android.view.View; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.List; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +public class ShadeViewDifferTest extends SysuiTestCase { + private ShadeViewDiffer mDiffer; + + private FakeController mRootController = new FakeController(mContext, "RootController"); + private FakeController mController1 = new FakeController(mContext, "Controller1"); + private FakeController mController2 = new FakeController(mContext, "Controller2"); + private FakeController mController3 = new FakeController(mContext, "Controller3"); + private FakeController mController4 = new FakeController(mContext, "Controller4"); + private FakeController mController5 = new FakeController(mContext, "Controller5"); + private FakeController mController6 = new FakeController(mContext, "Controller6"); + private FakeController mController7 = new FakeController(mContext, "Controller7"); + + @Mock + ShadeViewDifferLogger mLogger; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mDiffer = new ShadeViewDiffer(mRootController, mLogger); + } + + @Test + public void testAddInitialViews() { + // WHEN a spec is applied to an empty root + // THEN the final tree matches the spec + applySpecAndCheck( + node(mController1), + node(mController2, + node(mController3), + node(mController4) + ), + node(mController5) + ); + } + + @Test + public void testDetachViews() { + // GIVEN a preexisting tree of controllers + applySpecAndCheck( + node(mController1), + node(mController2, + node(mController3), + node(mController4) + ), + node(mController5) + ); + + // WHEN the new spec removes nodes + // THEN the final tree matches the spec + applySpecAndCheck( + node(mController5) + ); + } + + @Test + public void testReparentChildren() { + // GIVEN a preexisting tree of controllers + applySpecAndCheck( + node(mController1), + node(mController2, + node(mController3), + node(mController4) + ), + node(mController5) + ); + + // WHEN the parents of the controllers are all shuffled around + // THEN the final tree matches the spec + applySpecAndCheck( + node(mController1), + node(mController4), + node(mController3, + node(mController2) + ) + ); + } + + @Test + public void testReorderChildren() { + // GIVEN a preexisting tree of controllers + applySpecAndCheck( + node(mController1), + node(mController2), + node(mController3), + node(mController4) + ); + + // WHEN the children change order + // THEN the final tree matches the spec + applySpecAndCheck( + node(mController3), + node(mController2), + node(mController4), + node(mController1) + ); + } + + @Test + public void testRemovedGroupsAreKeptTogether() { + // GIVEN a preexisting tree with a group + applySpecAndCheck( + node(mController1), + node(mController2, + node(mController3), + node(mController4), + node(mController5) + ) + ); + + // WHEN the new spec removes the entire group + applySpecAndCheck( + node(mController1) + ); + + // THEN the group children are still attached to their parent + assertEquals(mController2.getView(), mController3.getView().getParent()); + assertEquals(mController2.getView(), mController4.getView().getParent()); + assertEquals(mController2.getView(), mController5.getView().getParent()); + } + + @Test + public void testUnmanagedViews() { + // GIVEN a preexisting tree of controllers + applySpecAndCheck( + node(mController1), + node(mController2, + node(mController3), + node(mController4) + ), + node(mController5) + ); + + // GIVEN some additional unmanaged views attached to the tree + View unmanagedView1 = new View(mContext); + View unmanagedView2 = new View(mContext); + + mRootController.getView().addView(unmanagedView1, 1); + mController2.getView().addView(unmanagedView2, 0); + + // WHEN a new spec is applied with additional nodes + // THEN the final tree matches the spec + applySpecAndCheck( + node(mController1), + node(mController2, + node(mController3), + node(mController4), + node(mController6) + ), + node(mController5), + node(mController7) + ); + + // THEN the unmanaged views have been pushed to the end of their parents + assertEquals(unmanagedView1, mRootController.view.getChildAt(4)); + assertEquals(unmanagedView2, mController2.view.getChildAt(3)); + } + + private void applySpecAndCheck(NodeSpec spec) { + mDiffer.applySpec(spec); + checkMatchesSpec(spec); + } + + private void applySpecAndCheck(SpecBuilder... children) { + applySpecAndCheck(node(mRootController, children).build()); + } + + private void checkMatchesSpec(NodeSpec spec) { + final NodeController parent = spec.getController(); + final List<NodeSpec> children = spec.getChildren(); + + for (int i = 0; i < children.size(); i++) { + NodeSpec childSpec = children.get(i); + View view = parent.getChildAt(i); + + assertEquals( + "Child " + i + " of parent " + parent.getNodeLabel() + " should be " + + childSpec.getController().getNodeLabel() + " but is instead " + + (view != null ? mDiffer.getViewLabel(view) : "null"), + view, + childSpec.getController().getView()); + + if (!childSpec.getChildren().isEmpty()) { + checkMatchesSpec(childSpec); + } + } + } + + private static class FakeController implements NodeController { + + public final FrameLayout view; + private final String mLabel; + + FakeController(Context context, String label) { + view = new FrameLayout(context); + mLabel = label; + } + + @NonNull + @Override + public String getNodeLabel() { + return mLabel; + } + + @NonNull + @Override + public FrameLayout getView() { + return view; + } + + @Override + public int getChildCount() { + return view.getChildCount(); + } + + @Override + public View getChildAt(int index) { + return view.getChildAt(index); + } + + @Override + public void addChildAt(@NonNull NodeController child, int index) { + view.addView(child.getView(), index); + } + + @Override + public void moveChildTo(@NonNull NodeController child, int index) { + view.removeView(child.getView()); + view.addView(child.getView(), index); + } + + @Override + public void removeChild(@NonNull NodeController child, boolean isTransfer) { + view.removeView(child.getView()); + } + } + + private static class SpecBuilder { + private final NodeController mController; + private final SpecBuilder[] mChildren; + + SpecBuilder(NodeController controller, SpecBuilder... children) { + mController = controller; + mChildren = children; + } + + public NodeSpec build() { + return build(null); + } + + public NodeSpec build(@Nullable NodeSpec parent) { + final NodeSpecImpl spec = new NodeSpecImpl(parent, mController); + for (SpecBuilder childBuilder : mChildren) { + spec.getChildren().add(childBuilder.build(spec)); + } + return spec; + } + } + + private static SpecBuilder node(NodeController controller, SpecBuilder... children) { + return new SpecBuilder(controller, children); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/AppOpsInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/AppOpsInfoTest.java deleted file mode 100644 index 43d8b50bcf72..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/AppOpsInfoTest.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright (C) 2018 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.statusbar.notification.row; - -import static android.app.AppOpsManager.OP_CAMERA; -import static android.app.AppOpsManager.OP_RECORD_AUDIO; -import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW; - -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertTrue; - -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.anyBoolean; -import static org.mockito.Mockito.anyInt; -import static org.mockito.Mockito.anyString; -import static org.mockito.Mockito.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.app.Notification; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.graphics.drawable.Drawable; -import android.os.UserHandle; -import android.service.notification.StatusBarNotification; -import android.test.suitebuilder.annotation.SmallTest; -import android.testing.AndroidTestingRunner; -import android.testing.UiThreadTest; -import android.util.ArraySet; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.ImageView; -import android.widget.TextView; - -import com.android.internal.logging.testing.UiEventLoggerFake; -import com.android.systemui.R; -import com.android.systemui.SysuiTestCase; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.concurrent.CountDownLatch; - -@SmallTest -@RunWith(AndroidTestingRunner.class) -@UiThreadTest -public class AppOpsInfoTest extends SysuiTestCase { - private static final String TEST_PACKAGE_NAME = "test_package"; - private static final int TEST_UID = 1; - - private AppOpsInfo mAppOpsInfo; - private final PackageManager mMockPackageManager = mock(PackageManager.class); - private final NotificationGuts mGutsParent = mock(NotificationGuts.class); - private StatusBarNotification mSbn; - private UiEventLoggerFake mUiEventLogger = new UiEventLoggerFake(); - - @Before - public void setUp() throws Exception { - // Inflate the layout - final LayoutInflater layoutInflater = LayoutInflater.from(mContext); - mAppOpsInfo = (AppOpsInfo) layoutInflater.inflate(R.layout.app_ops_info, null); - mAppOpsInfo.setGutsParent(mGutsParent); - - // PackageManager must return a packageInfo and applicationInfo. - final PackageInfo packageInfo = new PackageInfo(); - packageInfo.packageName = TEST_PACKAGE_NAME; - when(mMockPackageManager.getPackageInfo(eq(TEST_PACKAGE_NAME), anyInt())) - .thenReturn(packageInfo); - final ApplicationInfo applicationInfo = new ApplicationInfo(); - applicationInfo.uid = TEST_UID; // non-zero - when(mMockPackageManager.getApplicationInfo(anyString(), anyInt())).thenReturn( - applicationInfo); - - mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0, - new Notification(), UserHandle.CURRENT, null, 0); - } - - @Test - public void testBindNotification_SetsTextApplicationName() { - when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name"); - mAppOpsInfo.bindGuts(mMockPackageManager, null, mSbn, mUiEventLogger, new ArraySet<>()); - final TextView textView = mAppOpsInfo.findViewById(R.id.pkgname); - assertTrue(textView.getText().toString().contains("App Name")); - } - - @Test - public void testBindNotification_SetsPackageIcon() { - final Drawable iconDrawable = mock(Drawable.class); - when(mMockPackageManager.getApplicationIcon(any(ApplicationInfo.class))) - .thenReturn(iconDrawable); - mAppOpsInfo.bindGuts(mMockPackageManager, null, mSbn, mUiEventLogger, new ArraySet<>()); - final ImageView iconView = mAppOpsInfo.findViewById(R.id.pkgicon); - assertEquals(iconDrawable, iconView.getDrawable()); - } - - @Test - public void testBindNotification_SetsOnClickListenerForSettings() throws Exception { - ArraySet<Integer> expectedOps = new ArraySet<>(); - expectedOps.add(OP_CAMERA); - final CountDownLatch latch = new CountDownLatch(1); - mAppOpsInfo.bindGuts(mMockPackageManager, (View v, String pkg, int uid, - ArraySet<Integer> ops) -> { - assertEquals(TEST_PACKAGE_NAME, pkg); - assertEquals(expectedOps, ops); - assertEquals(TEST_UID, uid); - latch.countDown(); - }, mSbn, mUiEventLogger, expectedOps); - - final View settingsButton = mAppOpsInfo.findViewById(R.id.settings); - settingsButton.performClick(); - // Verify that listener was triggered. - assertEquals(0, latch.getCount()); - } - - @Test - public void testBindNotification_LogsOpen() throws Exception { - mAppOpsInfo.bindGuts(mMockPackageManager, null, mSbn, mUiEventLogger, new ArraySet<>()); - assertEquals(1, mUiEventLogger.numLogs()); - assertEquals(NotificationAppOpsEvent.NOTIFICATION_APP_OPS_OPEN.getId(), - mUiEventLogger.eventId(0)); - } - - @Test - public void testOk() { - ArraySet<Integer> expectedOps = new ArraySet<>(); - expectedOps.add(OP_CAMERA); - final CountDownLatch latch = new CountDownLatch(1); - mAppOpsInfo.bindGuts(mMockPackageManager, (View v, String pkg, int uid, - ArraySet<Integer> ops) -> { - assertEquals(TEST_PACKAGE_NAME, pkg); - assertEquals(expectedOps, ops); - assertEquals(TEST_UID, uid); - latch.countDown(); - }, mSbn, mUiEventLogger, expectedOps); - - final View okButton = mAppOpsInfo.findViewById(R.id.ok); - okButton.performClick(); - assertEquals(1, latch.getCount()); - verify(mGutsParent, times(1)).closeControls(eq(okButton), anyBoolean()); - } - - @Test - public void testPrompt_camera() { - ArraySet<Integer> expectedOps = new ArraySet<>(); - expectedOps.add(OP_CAMERA); - mAppOpsInfo.bindGuts(mMockPackageManager, null, mSbn, mUiEventLogger, expectedOps); - TextView prompt = mAppOpsInfo.findViewById(R.id.prompt); - assertEquals("This app is using the camera.", prompt.getText()); - } - - @Test - public void testPrompt_mic() { - ArraySet<Integer> expectedOps = new ArraySet<>(); - expectedOps.add(OP_RECORD_AUDIO); - mAppOpsInfo.bindGuts(mMockPackageManager, null, mSbn, mUiEventLogger, expectedOps); - TextView prompt = mAppOpsInfo.findViewById(R.id.prompt); - assertEquals("This app is using the microphone.", prompt.getText()); - } - - @Test - public void testPrompt_overlay() { - ArraySet<Integer> expectedOps = new ArraySet<>(); - expectedOps.add(OP_SYSTEM_ALERT_WINDOW); - mAppOpsInfo.bindGuts(mMockPackageManager, null, mSbn, mUiEventLogger, expectedOps); - TextView prompt = mAppOpsInfo.findViewById(R.id.prompt); - assertEquals("This app is displaying over other apps on your screen.", prompt.getText()); - } - - @Test - public void testPrompt_camera_mic() { - ArraySet<Integer> expectedOps = new ArraySet<>(); - expectedOps.add(OP_CAMERA); - expectedOps.add(OP_RECORD_AUDIO); - mAppOpsInfo.bindGuts(mMockPackageManager, null, mSbn, mUiEventLogger, expectedOps); - TextView prompt = mAppOpsInfo.findViewById(R.id.prompt); - assertEquals("This app is using the microphone and camera.", prompt.getText()); - } - - @Test - public void testPrompt_camera_mic_overlay() { - ArraySet<Integer> expectedOps = new ArraySet<>(); - expectedOps.add(OP_CAMERA); - expectedOps.add(OP_RECORD_AUDIO); - expectedOps.add(OP_SYSTEM_ALERT_WINDOW); - mAppOpsInfo.bindGuts(mMockPackageManager, null, mSbn, mUiEventLogger, expectedOps); - TextView prompt = mAppOpsInfo.findViewById(R.id.prompt); - assertEquals("This app is displaying over other apps on your screen and using" - + " the microphone and camera.", prompt.getText()); - } - - @Test - public void testPrompt_camera_overlay() { - ArraySet<Integer> expectedOps = new ArraySet<>(); - expectedOps.add(OP_CAMERA); - expectedOps.add(OP_SYSTEM_ALERT_WINDOW); - mAppOpsInfo.bindGuts(mMockPackageManager, null, mSbn, mUiEventLogger, expectedOps); - TextView prompt = mAppOpsInfo.findViewById(R.id.prompt); - assertEquals("This app is displaying over other apps on your screen and using" - + " the camera.", prompt.getText()); - } - - @Test - public void testPrompt_mic_overlay() { - ArraySet<Integer> expectedOps = new ArraySet<>(); - expectedOps.add(OP_RECORD_AUDIO); - expectedOps.add(OP_SYSTEM_ALERT_WINDOW); - mAppOpsInfo.bindGuts(mMockPackageManager, null, mSbn, mUiEventLogger, expectedOps); - TextView prompt = mAppOpsInfo.findViewById(R.id.prompt); - assertEquals("This app is displaying over other apps on your screen and using" - + " the microphone.", prompt.getText()); - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java index dc4a6ca14a77..f29b46c73e4d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java @@ -35,12 +35,10 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.app.AppOpsManager; import android.app.NotificationChannel; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; -import android.util.ArraySet; import android.view.View; import androidx.test.filters.SmallTest; @@ -213,46 +211,6 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { } @Test - public void testShowAppOps_noHeader() { - // public notification is custom layout - no header - mGroupRow.setSensitive(true, true); - mGroupRow.setAppOpsOnClickListener(null); - mGroupRow.showAppOpsIcons(null); - } - - @Test - public void testShowAppOpsIcons_header() { - NotificationContentView publicLayout = mock(NotificationContentView.class); - mGroupRow.setPublicLayout(publicLayout); - NotificationContentView privateLayout = mock(NotificationContentView.class); - mGroupRow.setPrivateLayout(privateLayout); - NotificationChildrenContainer mockContainer = mock(NotificationChildrenContainer.class); - when(mockContainer.getNotificationChildCount()).thenReturn(1); - mGroupRow.setChildrenContainer(mockContainer); - - ArraySet<Integer> ops = new ArraySet<>(); - ops.add(AppOpsManager.OP_ANSWER_PHONE_CALLS); - mGroupRow.showAppOpsIcons(ops); - - verify(mockContainer, times(1)).showAppOpsIcons(ops); - verify(privateLayout, times(1)).showAppOpsIcons(ops); - verify(publicLayout, times(1)).showAppOpsIcons(ops); - - } - - @Test - public void testAppOpsOnClick() { - ExpandableNotificationRow.CoordinateOnClickListener l = mock( - ExpandableNotificationRow.CoordinateOnClickListener.class); - View view = mock(View.class); - - mGroupRow.setAppOpsOnClickListener(l); - - mGroupRow.getAppOpsOnClickListener().onClick(view); - verify(l, times(1)).onClick(any(), anyInt(), anyInt(), any()); - } - - @Test public void testFeedback_noHeader() { // public notification is custom layout - no header mGroupRow.setSensitive(true, true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java index 6d4a7115b8c4..c2091da2347e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java @@ -76,32 +76,6 @@ public class NotificationContentViewTest extends SysuiTestCase { @Test @UiThreadTest - public void testShowAppOpsIcons() { - View mockContracted = mock(NotificationHeaderView.class); - when(mockContracted.findViewById(com.android.internal.R.id.mic)) - .thenReturn(mockContracted); - View mockExpanded = mock(NotificationHeaderView.class); - when(mockExpanded.findViewById(com.android.internal.R.id.mic)) - .thenReturn(mockExpanded); - View mockHeadsUp = mock(NotificationHeaderView.class); - when(mockHeadsUp.findViewById(com.android.internal.R.id.mic)) - .thenReturn(mockHeadsUp); - - mView.setContractedChild(mockContracted); - mView.setExpandedChild(mockExpanded); - mView.setHeadsUpChild(mockHeadsUp); - - ArraySet<Integer> ops = new ArraySet<>(); - ops.add(AppOpsManager.OP_RECORD_AUDIO); - mView.showAppOpsIcons(ops); - - verify(mockContracted, times(1)).setVisibility(View.VISIBLE); - verify(mockExpanded, times(1)).setVisibility(View.VISIBLE); - verify(mockHeadsUp, times(1)).setVisibility(View.VISIBLE); - } - - @Test - @UiThreadTest public void testShowFeedbackIcon() { View mockContracted = mock(NotificationHeaderView.class); when(mockContracted.findViewById(com.android.internal.R.id.feedback)) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java index a90af87064b5..7a0a19bd5424 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java @@ -221,6 +221,7 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase { .thenAnswer((Answer<ExpandableNotificationRowController>) invocation -> new ExpandableNotificationRowController( viewCaptor.getValue(), + mListContainer, mock(ActivatableNotificationViewController.class), mNotificationMediaManager, mock(PluginManager.class), diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java index 14994d55852f..54ccc4d8320d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java @@ -79,7 +79,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener; -import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; +import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.DeviceProvisionedController; @@ -117,7 +117,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { @Mock private VisualStabilityManager mVisualStabilityManager; @Mock private NotificationPresenter mPresenter; @Mock private NotificationActivityStarter mNotificationActivityStarter; - @Mock private NotificationStackScrollLayout mStackScroller; + @Mock private NotificationListContainer mNotificationListContainer; @Mock private NotificationInfo.CheckSaveListener mCheckSaveListener; @Mock private OnSettingsClickListener mOnSettingsClickListener; @Mock private DeviceProvisionedController mDeviceProvisionedController; @@ -156,7 +156,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { mChannelEditorDialogController, mContextTracker, mProvider, mAssistantFeedbackController, mBubbleController, new UiEventLoggerFake()); - mGutsManager.setUpWithPresenter(mPresenter, mStackScroller, + mGutsManager.setUpWithPresenter(mPresenter, mNotificationListContainer, mCheckSaveListener, mOnSettingsClickListener); mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java index 8ccbb2ebb0db..123be9f92b8a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java @@ -422,7 +422,6 @@ public class NotificationTestHelper { mock(OnExpandClickListener.class), mock(NotificationMediaManager.class), mock(ExpandableNotificationRow.CoordinateOnClickListener.class), - mock(ExpandableNotificationRow.CoordinateOnClickListener.class), mock(FalsingManager.class), mStatusBarStateController, mPeopleNotificationIdentifier); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java index 3e469073694f..ccdc69aeaa18 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java @@ -34,6 +34,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.view.AppearanceRegion; import com.android.systemui.SysuiTestCase; +import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.statusbar.policy.BatteryController; import org.junit.Before; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java index d1a439f99702..18cb6675f384 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java @@ -18,7 +18,6 @@ package com.android.systemui.statusbar.phone; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -29,6 +28,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.demomode.DemoModeController; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.NotificationMediaManager; @@ -66,6 +66,7 @@ public class NotificationIconAreaControllerTest extends SysuiTestCase { private NotificationIconAreaController mController; @Mock private BubbleController mBubbleController; + @Mock private DemoModeController mDemoModeController; @Before public void setup() { @@ -77,7 +78,8 @@ public class NotificationIconAreaControllerTest extends SysuiTestCase { mController = new NotificationIconAreaController(mContext, mStatusBar, mStatusBarStateController, mWakeUpCoordinator, mKeyguardBypassController, - mNotificationMediaManager, mListener, mDozeParameters, mBubbleController); + mNotificationMediaManager, mListener, mDozeParameters, mBubbleController, + mDemoModeController); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java index f66fd5677a5d..a0c0e7979084 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java @@ -72,7 +72,6 @@ import com.android.systemui.statusbar.notification.ConversationNotificationManag import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; -import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; @@ -188,6 +187,9 @@ public class NotificationPanelViewTest extends SysuiTestCase { private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; @Mock private KeyguardClockSwitchController mKeyguardClockSwitchController; + @Mock + private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController; + private NotificationPanelViewController mNotificationPanelViewController; private View.AccessibilityDelegate mAccessibiltyDelegate; @@ -205,8 +207,11 @@ public class NotificationPanelViewTest extends SysuiTestCase { when(mView.findViewById(R.id.keyguard_clock_container)).thenReturn(mKeyguardClockSwitch); when(mView.findViewById(R.id.notification_stack_scroller)) .thenReturn(mNotificationStackScrollLayout); - when(mNotificationStackScrollLayout.getHeight()).thenReturn(1000); - when(mNotificationStackScrollLayout.getHeadsUpCallback()).thenReturn(mHeadsUpCallback); + when(mNotificationStackScrollLayout.getController()) + .thenReturn(mNotificationStackScrollLayoutController); + when(mNotificationStackScrollLayoutController.getHeight()).thenReturn(1000); + when(mNotificationStackScrollLayoutController.getHeadsUpCallback()) + .thenReturn(mHeadsUpCallback); when(mView.findViewById(R.id.keyguard_bottom_area)).thenReturn(mKeyguardBottomArea); when(mKeyguardBottomArea.getLeftView()).thenReturn(mock(KeyguardAffordanceView.class)); when(mKeyguardBottomArea.getRightView()).thenReturn(mock(KeyguardAffordanceView.class)); @@ -233,11 +238,6 @@ public class NotificationPanelViewTest extends SysuiTestCase { mock(NotificationRoundnessManager.class), mStatusBarStateController, new FalsingManagerFake()); - NotificationStackScrollLayoutController notificationStackScrollLayoutController = - new NotificationStackScrollLayoutController( - true /* allowLongPress */, - mock(NotificationGutsManager.class) - ); mNotificationPanelViewController = new NotificationPanelViewController(mView, mInjectionInflationController, coordinator, expansionHandler, mDynamicPrivacyController, mKeyguardBypassController, @@ -251,7 +251,7 @@ public class NotificationPanelViewTest extends SysuiTestCase { mConversationNotificationManager, mMediaHiearchyManager, mBiometricUnlockController, mStatusBarKeyguardViewManager, () -> mKeyguardClockSwitchController, - notificationStackScrollLayoutController); + mNotificationStackScrollLayoutController); mNotificationPanelViewController.initDependencies(mStatusBar, mGroupManager, mNotificationShelfController, mNotificationAreaController, mScrimController); mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager); @@ -267,8 +267,10 @@ public class NotificationPanelViewTest extends SysuiTestCase { public void testSetDozing_notifiesNsslAndStateController() { mNotificationPanelViewController.setDozing(true /* dozing */, true /* animate */, null /* touch */); - InOrder inOrder = inOrder(mNotificationStackScrollLayout, mStatusBarStateController); - inOrder.verify(mNotificationStackScrollLayout).setDozing(eq(true), eq(true), eq(null)); + InOrder inOrder = inOrder( + mNotificationStackScrollLayoutController, mStatusBarStateController); + inOrder.verify(mNotificationStackScrollLayoutController) + .setDozing(eq(true), eq(true), eq(null)); inOrder.verify(mStatusBarStateController).setDozeAmount(eq(1f), eq(true)); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java index e04d25b17c71..51900cb7dda1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java @@ -100,7 +100,9 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase { mController = new NotificationShadeWindowViewController( new InjectionInflationController( - SystemUIFactory.getInstance().getRootComponent()), + SystemUIFactory.getInstance() + .getRootComponent() + .createViewInstanceCreatorFactory()), mCoordinator, mPulseExpansionHandler, mDynamicPrivacyController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java index 675a2df768d8..50d891efc62c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java @@ -43,6 +43,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.dock.DockManager; import com.android.systemui.keyguard.DismissCallbackRegistry; +import com.android.systemui.navigationbar.NavigationModeController; import com.android.systemui.plugins.ActivityStarter.OnDismissAction; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.statusbar.NotificationMediaManager; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java index 33067343ba40..a71b10cf9264 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java @@ -184,7 +184,6 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { getContext(), mock(CommandQueue.class), mHandler, - mHandler, mUiBgExecutor, mEntryManager, mNotifPipeline, @@ -234,9 +233,6 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { // set up Handler to synchronously invoke the Runnable arg doAnswer(answerVoid(Runnable::run)) .when(mHandler).post(any(Runnable.class)); - - doAnswer(answerVoid(Runnable::run)) - .when(mHandler).postAtFrontOfQueue(any(Runnable.class)); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java index 318e9b87fa70..e4f481241257 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java @@ -23,13 +23,11 @@ import static org.mockito.Mockito.when; import android.app.Notification; import android.app.StatusBarManager; -import android.content.Context; import android.metrics.LogMaker; import android.support.test.metricshelper.MetricsAsserts; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; -import android.view.ViewGroup; import androidx.test.filters.SmallTest; @@ -59,6 +57,8 @@ import com.android.systemui.statusbar.notification.interruption.NotificationInte import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.policy.KeyguardStateController; import org.junit.Before; @@ -112,11 +112,17 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { NotificationShadeWindowView notificationShadeWindowView = mock(NotificationShadeWindowView.class); + NotificationStackScrollLayoutController stackScrollLayoutController = + mock(NotificationStackScrollLayoutController.class); + when(stackScrollLayoutController.getView()).thenReturn( + mock(NotificationStackScrollLayout.class)); + when(stackScrollLayoutController.getNotificationListContainer()).thenReturn( + mock(NotificationListContainer.class)); when(notificationShadeWindowView.getResources()).thenReturn(mContext.getResources()); mStatusBarNotificationPresenter = new StatusBarNotificationPresenter(mContext, mock(NotificationPanelViewController.class), mock(HeadsUpManagerPhone.class), - notificationShadeWindowView, mock(NotificationListContainerViewGroup.class), + notificationShadeWindowView, stackScrollLayoutController, mock(DozeScrimController.class), mock(ScrimController.class), mock(ActivityLaunchAnimator.class), mock(DynamicPrivacyController.class), mock(KeyguardStateController.class), @@ -205,14 +211,4 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { new LogMaker(MetricsEvent.ACTION_LS_NOTE) .setType(MetricsEvent.TYPE_ACTION)); } - - // We need this because mockito doesn't know how to construct a mock that extends ViewGroup - // and implements NotificationListContainer without it because of classloader issues. - private abstract static class NotificationListContainerViewGroup extends ViewGroup - implements NotificationListContainer { - - public NotificationListContainerViewGroup(Context context) { - super(context); - } - } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index 5a08c9ca017b..aa0940698510 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -83,10 +83,12 @@ import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.bubbles.BubbleController; import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.colorextraction.SysuiColorExtractor; +import com.android.systemui.demomode.DemoModeController; import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.keyguard.WakefulnessLifecycle; +import com.android.systemui.navigationbar.NavigationBarController; import com.android.systemui.plugins.ActivityStarter.OnDismissAction; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.PluginDependencyProvider; @@ -97,7 +99,6 @@ import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.stackdivider.Divider; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.KeyguardIndicationController; -import com.android.systemui.statusbar.NavigationBarController; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationMediaManager; @@ -124,7 +125,9 @@ import com.android.systemui.statusbar.notification.interruption.NotificationInte import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerFake; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; +import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.ConfigurationController; @@ -171,6 +174,8 @@ public class StatusBarTest extends SysuiTestCase { @Mock private KeyguardStateController mKeyguardStateController; @Mock private KeyguardIndicationController mKeyguardIndicationController; @Mock private NotificationStackScrollLayout mStackScroller; + @Mock private NotificationStackScrollLayoutController mStackScrollerController; + @Mock private NotificationListContainer mNotificationListContainer; @Mock private HeadsUpManagerPhone mHeadsUpManager; @Mock private NotificationPanelViewController mNotificationPanelViewController; @Mock private NotificationPanelView mNotificationPanelView; @@ -248,6 +253,7 @@ public class StatusBarTest extends SysuiTestCase { @Mock private ExtensionController mExtensionController; @Mock private UserInfoControllerImpl mUserInfoControllerImpl; @Mock private PhoneStatusBarPolicy mPhoneStatusBarPolicy; + @Mock private DemoModeController mDemoModeController; @Mock private Lazy<NotificationShadeDepthController> mNotificationShadeDepthControllerLazy; private ShadeController mShadeController; private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock()); @@ -283,6 +289,10 @@ public class StatusBarTest extends SysuiTestCase { mContext.setTheme(R.style.Theme_SystemUI_Light); + when(mStackScroller.getController()).thenReturn(mStackScrollerController); + when(mStackScrollerController.getView()).thenReturn(mStackScroller); + when(mStackScrollerController.getNotificationListContainer()).thenReturn( + mNotificationListContainer); when(mStackScroller.generateLayoutParams(any())).thenReturn(new LayoutParams(0, 0)); when(mNotificationPanelViewController.getView()).thenReturn(mNotificationPanelView); when(mNotificationPanelView.getLayoutParams()).thenReturn(new LayoutParams(0, 0)); @@ -403,6 +413,7 @@ public class StatusBarTest extends SysuiTestCase { mPhoneStatusBarPolicy, mKeyguardIndicationController, mDismissCallbackRegistry, + mDemoModeController, mNotificationShadeDepthControllerLazy, mStatusBarTouchableRegionManager); @@ -429,7 +440,7 @@ public class StatusBarTest extends SysuiTestCase { mStatusBar.mStackScroller = mStackScroller; mStatusBar.startKeyguard(); mInitController.executePostInitTasks(); - notificationLogger.setUpWithContainer(mStackScroller); + notificationLogger.setUpWithContainer(mNotificationListContainer); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java index eca48c8c2ee1..23fa6fd5e4ca 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java @@ -29,6 +29,7 @@ import android.testing.TestableLooper; import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.demomode.DemoModeController; import com.android.systemui.power.EnhancedEstimates; import org.junit.Assert; @@ -44,17 +45,21 @@ import org.mockito.MockitoAnnotations; @TestableLooper.RunWithLooper public class BatteryControllerTest extends SysuiTestCase { - @Mock - private PowerManager mPowerManager; - @Mock - private BroadcastDispatcher mBroadcastDispatcher; + @Mock private PowerManager mPowerManager; + @Mock private BroadcastDispatcher mBroadcastDispatcher; + @Mock private DemoModeController mDemoModeController; private BatteryControllerImpl mBatteryController; @Before public void setUp() { MockitoAnnotations.initMocks(this); - mBatteryController = new BatteryControllerImpl(getContext(), mock(EnhancedEstimates.class), - mPowerManager, mBroadcastDispatcher, new Handler(), new Handler()); + mBatteryController = new BatteryControllerImpl(getContext(), + mock(EnhancedEstimates.class), + mPowerManager, + mBroadcastDispatcher, + mDemoModeController, + new Handler(), + new Handler()); mBatteryController.init(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java index aef454fc1374..7db1b836f428 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java @@ -66,6 +66,7 @@ import com.android.settingslib.net.DataUsageController; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.demomode.DemoModeController; import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener; import com.android.systemui.statusbar.policy.NetworkController.IconState; import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; @@ -113,6 +114,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase { protected DeviceProvisionedController mMockProvisionController; protected DeviceProvisionedListener mUserCallback; protected Instrumentation mInstrumentation; + protected DemoModeController mDemoModeController; protected int mSubId; @@ -146,6 +148,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase { res.addOverride(R.string.cell_data_off_content_description, NO_DATA_STRING); res.addOverride(R.string.not_default_data_content_description, NOT_DEFAULT_DATA_STRING); + mDemoModeController = mock(DemoModeController.class); mMockWm = mock(WifiManager.class); mMockTm = mock(TelephonyManager.class); mMockSm = mock(SubscriptionManager.class); @@ -200,10 +203,21 @@ public class NetworkControllerBaseTest extends SysuiTestCase { return null; }).when(mMockProvisionController).addCallback(any()); - mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, - mMockNsm, mMockSm, mConfig, TestableLooper.get(this).getLooper(), mCallbackHandler, - mock(AccessPointControllerImpl.class), mock(DataUsageController.class), - mMockSubDefaults, mMockProvisionController, mMockBd); + mNetworkController = new NetworkControllerImpl(mContext, + mMockCm, + mMockTm, + mMockWm, + mMockNsm, + mMockSm, + mConfig, + TestableLooper.get(this).getLooper(), + mCallbackHandler, + mock(AccessPointControllerImpl.class), + mock(DataUsageController.class), + mMockSubDefaults, + mMockProvisionController, + mMockBd, + mDemoModeController); setupNetworkController(); // Trigger blank callbacks to always get the current state (some tests don't trigger @@ -254,7 +268,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase { mConfig, TestableLooper.get(this).getLooper(), mCallbackHandler, mock(AccessPointControllerImpl.class), mock(DataUsageController.class), mMockSubDefaults, - mock(DeviceProvisionedController.class), mMockBd); + mock(DeviceProvisionedController.class), mMockBd, mDemoModeController); setupNetworkController(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java index 6fffcff41a4f..d8aa29e9f766 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java @@ -106,7 +106,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { mMockNsm, mMockSm, mConfig, Looper.getMainLooper(), mCallbackHandler, mock(AccessPointControllerImpl.class), mock(DataUsageController.class), mMockSubDefaults, - mock(DeviceProvisionedController.class), mMockBd); + mock(DeviceProvisionedController.class), mMockBd, mDemoModeController); setupNetworkController(); setupDefaultSignal(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java index 3b2743775721..61f71b758d80 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java @@ -63,7 +63,8 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockNsm, mMockSm, mConfig, Looper.getMainLooper(), mCallbackHandler, mock(AccessPointControllerImpl.class), mock(DataUsageController.class), - mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd); + mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd, + mDemoModeController); setupNetworkController(); verifyLastMobileDataIndicators(false, -1, 0); @@ -81,7 +82,8 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockNsm, mMockSm, mConfig, Looper.getMainLooper(), mCallbackHandler, mock(AccessPointControllerImpl.class), mock(DataUsageController.class), - mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd); + mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd, + mDemoModeController); mNetworkController.registerListeners(); // Wait for the main looper to execute the previous command @@ -147,7 +149,8 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { mNetworkController = new NetworkControllerImpl(mContext, mMockCm, mMockTm, mMockWm, mMockNsm, mMockSm, mConfig, Looper.getMainLooper(), mCallbackHandler, mock(AccessPointControllerImpl.class), mock(DataUsageController.class), - mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd); + mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd, + mDemoModeController); setupNetworkController(); // No Subscriptions. diff --git a/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java index 9bb01ae5df1d..64be2d9a5599 100644 --- a/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java +++ b/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java @@ -50,7 +50,7 @@ import androidx.test.InstrumentationRegistry; import androidx.test.filters.MediumTest; import androidx.test.runner.AndroidJUnit4; -import com.android.testutils.HandlerUtilsKt; +import com.android.testutils.HandlerUtils; import com.android.testutils.TapPacketReader; import org.junit.After; @@ -366,7 +366,7 @@ public class EthernetTetheringTest { private TapPacketReader makePacketReader(FileDescriptor fd, int mtu) { final TapPacketReader reader = new TapPacketReader(mHandler, fd, mtu); mHandler.post(() -> reader.start()); - HandlerUtilsKt.waitForIdle(mHandler, TIMEOUT_MS); + HandlerUtils.waitForIdle(mHandler, TIMEOUT_MS); return reader; } diff --git a/packages/Tethering/tests/unit/src/android/net/util/TetheringUtilsTest.java b/packages/Tethering/tests/unit/src/android/net/util/TetheringUtilsTest.java index 1499f3be224e..91c7771cc7fe 100644 --- a/packages/Tethering/tests/unit/src/android/net/util/TetheringUtilsTest.java +++ b/packages/Tethering/tests/unit/src/android/net/util/TetheringUtilsTest.java @@ -27,7 +27,7 @@ import android.net.TetheringRequestParcel; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import com.android.testutils.MiscAssertsKt; +import com.android.testutils.MiscAsserts; import org.junit.Before; import org.junit.Test; @@ -82,6 +82,6 @@ public class TetheringUtilsTest { request.showProvisioningUi = false; assertFalse(TetheringUtils.isTetheringRequestEquals(mTetheringRequest, request)); - MiscAssertsKt.assertFieldCountEquals(5, TetheringRequestParcel.class); + MiscAsserts.assertFieldCountEquals(5, TetheringRequestParcel.class); } } diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java index b291438937c7..ce52ae22ece8 100644 --- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java +++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java @@ -30,8 +30,8 @@ import static com.android.networkstack.tethering.OffloadController.StatsType.STA import static com.android.networkstack.tethering.OffloadController.StatsType.STATS_PER_UID; import static com.android.networkstack.tethering.OffloadHardwareInterface.ForwardedStats; import static com.android.networkstack.tethering.TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS; -import static com.android.testutils.MiscAssertsKt.assertContainsAll; -import static com.android.testutils.MiscAssertsKt.assertThrows; +import static com.android.testutils.MiscAsserts.assertContainsAll; +import static com.android.testutils.MiscAsserts.assertThrows; import static com.android.testutils.NetworkStatsUtilsKt.assertNetworkStatsEquals; import static junit.framework.Assert.assertNotNull; diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index 46fe5cf093fd..1fe3840b51a8 100644 --- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -143,7 +143,7 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.StateMachine; import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.internal.util.test.FakeSettingsProvider; -import com.android.testutils.MiscAssertsKt; +import com.android.testutils.MiscAsserts; import org.junit.After; import org.junit.AfterClass; @@ -1360,7 +1360,7 @@ public class TetheringTest { assertEquals(0, parcel.localOnlyList.length); assertEquals(0, parcel.erroredIfaceList.length); assertEquals(0, parcel.lastErrorList.length); - MiscAssertsKt.assertFieldCountEquals(5, TetherStatesParcel.class); + MiscAsserts.assertFieldCountEquals(5, TetherStatesParcel.class); } @Test diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java index c45da8668087..a2d58c8019fc 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java @@ -631,7 +631,7 @@ public class TouchExplorer extends BaseEventStreamTransformation // Two pointers moving in the same direction within // a given distance perform a drag. mState.startDragging(); - adjustEventLocationForDrag(event); + computeDraggingPointerIdIfNeeded(event); pointerIdBits = 1 << mDraggingPointerId; event.setEdgeFlags(mReceivedPointerTracker.getLastReceivedDownEdgeFlags()); mDispatcher.sendMotionEvent( @@ -794,7 +794,7 @@ public class TouchExplorer extends BaseEventStreamTransformation case 2: if (isDraggingGesture(event)) { // If still dragging send a drag event. - adjustEventLocationForDrag(event); + computeDraggingPointerIdIfNeeded(event); mDispatcher.sendMotionEvent( event, ACTION_MOVE, rawEvent, pointerIdBits, policyFlags); } else { @@ -959,44 +959,27 @@ public class TouchExplorer extends BaseEventStreamTransformation } /** - * Adjust the location of an injected event when performing a drag. The location will be the - * location of the finger closest to an edge of the screen. + * Computes {@link #mDraggingPointerId} if it is invalid. The pointer will be the finger + * closet to an edge of the screen. */ - private void adjustEventLocationForDrag(MotionEvent event) { + private void computeDraggingPointerIdIfNeeded(MotionEvent event) { + if (mDraggingPointerId != INVALID_POINTER_ID) { + // If we have a valid pointer ID, we should be good + final int pointerIndex = event.findPointerIndex(mDraggingPointerId); + if (event.findPointerIndex(pointerIndex) >= 0) { + return; + } + } + // Use the pointer that is closest to its closest edge. final float firstPtrX = event.getX(0); final float firstPtrY = event.getY(0); final int firstPtrId = event.getPointerId(0); final float secondPtrX = event.getX(1); final float secondPtrY = event.getY(1); final int secondPtrId = event.getPointerId(1); - float draggingX = firstPtrX; - float draggingY = firstPtrY; - if (mDraggingPointerId != INVALID_POINTER_ID) { - // Just use the coordinates of the dragging pointer. - int pointerIndex = event.findPointerIndex(mDraggingPointerId); - if (pointerIndex >= 0) { - draggingX = event.getX(pointerIndex); - draggingY = event.getY(pointerIndex); - } else { - // We've lost track of the dragging pointer. Try to recover by invalidating it. - // We'll the drop into the code below to choose a new one. - mDraggingPointerId = INVALID_POINTER_ID; - } - } - // Not quite an else, since the above code can invalidate the pointer - if (mDraggingPointerId == INVALID_POINTER_ID) { - // The goal is to use the coordinates of the finger that is closest to its closest edge. - if (getDistanceToClosestEdge(firstPtrX, firstPtrY) - < getDistanceToClosestEdge(secondPtrX, secondPtrY)) { - // X and Y initialized to firstPtrX and Y was right - mDraggingPointerId = firstPtrId; - } else { - draggingX = secondPtrX; - draggingY = secondPtrY; - mDraggingPointerId = secondPtrId; - } - } - event.setLocation(draggingX, draggingY); + mDraggingPointerId = (getDistanceToClosestEdge(firstPtrX, firstPtrY) + < getDistanceToClosestEdge(secondPtrX, secondPtrY)) + ? firstPtrId : secondPtrId; } private float getDistanceToClosestEdge(float x, float y) { diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index 663fd6259fd4..ad85784ca066 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -360,7 +360,7 @@ public final class AutofillManagerService @Override // from SystemService public boolean isUserSupported(TargetUser user) { - return user.getUserInfo().isFull() || user.getUserInfo().isManagedProfile(); + return user.isFull() || user.isManagedProfile(); } @Override // from SystemService diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java index 29235dd1ee72..e68c07ed73f7 100644 --- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java +++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java @@ -441,6 +441,7 @@ public class UserBackupManagerService { private long mAncestralToken = 0; private long mCurrentToken = 0; @Nullable private File mAncestralSerialNumberFile; + @OperationType private volatile long mAncestralOperationType; private final ContentObserver mSetupObserver; private final BroadcastReceiver mRunInitReceiver; @@ -881,6 +882,10 @@ public class UserBackupManagerService { mAncestralToken = ancestralToken; } + public void setAncestralOperationType(@OperationType int operationType) { + mAncestralOperationType = operationType; + } + public long getCurrentToken() { return mCurrentToken; } @@ -1808,6 +1813,16 @@ public class UserBackupManagerService { } } + private BackupEligibilityRules getEligibilityRulesForRestoreAtInstall(long restoreToken) { + if (mAncestralOperationType == OperationType.MIGRATION && restoreToken == mAncestralToken) { + return getEligibilityRulesForOperation(OperationType.MIGRATION); + } else { + // If we're not using the ancestral data set, it means we're restoring from a backup + // that happened on this device. + return mScheduledBackupEligibility; + } + } + /** * Get the restore-set token for the best-available restore set for this {@code packageName}: * the active set if possible, else the ancestral one. Returns zero if none available. @@ -3976,7 +3991,7 @@ public class UserBackupManagerService { packageName, token, listener, - mScheduledBackupEligibility); + getEligibilityRulesForRestoreAtInstall(restoreSet)); mBackupHandler.sendMessage(msg); } catch (Exception e) { // Calling into the transport broke; back off and proceed with the installation. diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java index 622067999f27..b9625397d237 100644 --- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java +++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java @@ -27,6 +27,7 @@ import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_OPERA import android.app.ApplicationThreadConstants; import android.app.IBackupAgent; +import android.app.backup.BackupManager; import android.app.backup.FullBackup; import android.app.backup.IBackupManagerMonitor; import android.app.backup.IFullBackupRestoreObserver; @@ -633,7 +634,11 @@ public class FullRestoreEngine extends RestoreEngine { setRunning(false); } - private static boolean isRestorableFile(FileMetadata info) { + private boolean isRestorableFile(FileMetadata info) { + if (mBackupEligibilityRules.getOperationType() == BackupManager.OperationType.MIGRATION) { + // Everything is eligible for device-to-device migration. + return true; + } if (FullBackup.CACHE_TREE_TOKEN.equals(info.domain)) { if (MORE_DEBUG) { Slog.i(TAG, "Dropping cache file path " + info.path); diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java index 7baf55992770..abf11bd542a1 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java @@ -1136,6 +1136,8 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { if (mIsSystemRestore && mPmAgent != null) { backupManagerService.setAncestralPackages(mPmAgent.getRestoredPackages()); backupManagerService.setAncestralToken(mToken); + backupManagerService.setAncestralOperationType( + mBackupEligibilityRules.getOperationType()); backupManagerService.writeRestoreTokens(); } diff --git a/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java b/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java index d6598975a647..73ba1f19c092 100644 --- a/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java +++ b/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java @@ -85,12 +85,15 @@ public class BackupEligibilityRules { * <li>they run as a system-level uid but do not supply their own backup agent * <li>it is the special shared-storage backup package used for 'adb backup' * </ol> + * + * However, the above eligibility rules are ignored for non-system apps in in case of + * device-to-device migration, see {@link OperationType}. */ @VisibleForTesting public boolean appIsEligibleForBackup(ApplicationInfo app) { - // 1. their manifest states android:allowBackup="false" - boolean appAllowsBackup = (app.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0; - if (!appAllowsBackup && !forceFullBackup(app.uid, mOperationType)) { + // 1. their manifest states android:allowBackup="false" and this is not a device-to-device + // migration + if (!isAppBackupAllowed(app)) { return false; } @@ -123,6 +126,23 @@ public class BackupEligibilityRules { } /** + * Check if this app allows backup. Apps can opt out of backup by stating + * android:allowBackup="false" in their manifest. However, this flag is ignored for non-system + * apps during device-to-device migrations, see {@link OperationType}. + * + * @param app The app under check. + * @return boolean indicating whether backup is allowed. + */ + public boolean isAppBackupAllowed(ApplicationInfo app) { + if (mOperationType == OperationType.MIGRATION && !UserHandle.isCore(app.uid)) { + // Backup / restore of all apps is force allowed during device-to-device migration. + return true; + } + + return (app.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0; + } + + /** * Returns whether an app is eligible for backup at runtime. That is, the app has to: * <ol> * <li>Return true for {@link #appIsEligibleForBackup(ApplicationInfo, int)} diff --git a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java index bf8e9c8512ae..3789fa14e87b 100644 --- a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java +++ b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java @@ -402,7 +402,7 @@ public class TarBackupReader { info.packageName, PackageManager.GET_SIGNING_CERTIFICATES, userId); // Fall through to IGNORE if the app explicitly disallows backup final int flags = pkgInfo.applicationInfo.flags; - if ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) { + if (eligibilityRules.isAppBackupAllowed(pkgInfo.applicationInfo)) { // Restore system-uid-space packages only if they have // defined a custom backup agent if (!UserHandle.isCore(pkgInfo.applicationInfo.uid) diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java index ea94ad0b3c20..e742015916e7 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java @@ -219,7 +219,7 @@ public final class ContentCaptureManagerService extends @Override // from SystemService public boolean isUserSupported(TargetUser user) { - return user.getUserInfo().isFull() || user.getUserInfo().isManagedProfile(); + return user.isFull() || user.isManagedProfile(); } @Override // from SystemService diff --git a/services/core/java/android/os/UserManagerInternal.java b/services/core/java/android/os/UserManagerInternal.java index fbe8c04bd59c..61e8128bd510 100644 --- a/services/core/java/android/os/UserManagerInternal.java +++ b/services/core/java/android/os/UserManagerInternal.java @@ -262,8 +262,7 @@ public abstract class UserManagerInternal { public abstract boolean hasUserRestriction(String restriction, int userId); /** - * Gets an {@link UserInfo} for the given {@code userId}, or {@code null} if not - * found. + * Gets a {@link UserInfo} for the given {@code userId}, or {@code null} if not found. */ public abstract @Nullable UserInfo getUserInfo(@UserIdInt int userId); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index ef62a991f323..bd590d317910 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -4966,7 +4966,7 @@ public class ConnectivityService extends IConnectivityManager.Stub Slog.w(TAG, "User " + userId + " has no Vpn configuration"); return null; } - return vpn.getLockdownWhitelist(); + return vpn.getLockdownAllowlist(); } } diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 6402e07bddc3..b2f0c8376db1 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -1477,7 +1477,7 @@ public class IpSecService extends IIpSecService.Stub { } /** - * Checks an IpSecConfig parcel to ensure that the contents are sane and throws an + * Checks an IpSecConfig parcel to ensure that the contents are valid and throws an * IllegalArgumentException if they are not. */ private void checkIpSecConfig(IpSecConfig config) { diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java index 0038dc2e8da0..b78b5d945a08 100644 --- a/services/core/java/com/android/server/ServiceWatcher.java +++ b/services/core/java/com/android/server/ServiceWatcher.java @@ -238,24 +238,13 @@ public class ServiceWatcher implements ServiceConnection { new PackageMonitor() { @Override - public void onPackageUpdateFinished(String packageName, int uid) { - ServiceWatcher.this.onPackageChanged(packageName); - } - - @Override - public void onPackageAdded(String packageName, int uid) { - ServiceWatcher.this.onPackageChanged(packageName); - } - - @Override - public void onPackageRemoved(String packageName, int uid) { - ServiceWatcher.this.onPackageChanged(packageName); + public boolean onPackageChanged(String packageName, int uid, String[] components) { + return true; } @Override - public boolean onPackageChanged(String packageName, int uid, String[] components) { - ServiceWatcher.this.onPackageChanged(packageName); - return super.onPackageChanged(packageName, uid, components); + public void onSomePackagesChanged() { + onBestServiceChanged(false); } }.register(mContext, UserHandle.ALL, true, mHandler); @@ -320,7 +309,7 @@ public class ServiceWatcher implements ServiceConnection { if (!mTargetService.equals(ServiceInfo.NONE)) { if (D) { - Log.i(TAG, "[" + mIntent.getAction() + "] unbinding from " + mTargetService); + Log.d(TAG, "[" + mIntent.getAction() + "] unbinding from " + mTargetService); } mContext.unbindService(this); @@ -335,9 +324,7 @@ public class ServiceWatcher implements ServiceConnection { Preconditions.checkState(mTargetService.component != null); - if (D) { - Log.i(TAG, getLogPrefix() + " binding to " + mTargetService); - } + Log.i(TAG, getLogPrefix() + " binding to " + mTargetService); Intent bindIntent = new Intent(mIntent).setComponent(mTargetService.component); if (!mContext.bindServiceAsUser(bindIntent, this, @@ -355,7 +342,7 @@ public class ServiceWatcher implements ServiceConnection { Preconditions.checkState(mBinder == null); if (D) { - Log.i(TAG, getLogPrefix() + " connected to " + component.toShortString()); + Log.d(TAG, getLogPrefix() + " connected to " + component.toShortString()); } mBinder = binder; @@ -379,7 +366,7 @@ public class ServiceWatcher implements ServiceConnection { } if (D) { - Log.i(TAG, getLogPrefix() + " disconnected from " + component.toShortString()); + Log.d(TAG, getLogPrefix() + " disconnected from " + component.toShortString()); } mBinder = null; @@ -392,13 +379,16 @@ public class ServiceWatcher implements ServiceConnection { public final void onBindingDied(ComponentName component) { Preconditions.checkState(Looper.myLooper() == mHandler.getLooper()); - if (D) { - Log.i(TAG, getLogPrefix() + " " + component.toShortString() + " died"); - } + Log.i(TAG, getLogPrefix() + " " + component.toShortString() + " died"); onBestServiceChanged(true); } + @Override + public final void onNullBinding(ComponentName component) { + Log.e(TAG, getLogPrefix() + " " + component.toShortString() + " has null binding"); + } + void onUserSwitched(@UserIdInt int userId) { mCurrentUserId = userId; onBestServiceChanged(false); @@ -410,11 +400,6 @@ public class ServiceWatcher implements ServiceConnection { } } - void onPackageChanged(String packageName) { - // force a rebind if the changed package was the currently connected package - onBestServiceChanged(packageName.equals(mTargetService.getPackageName())); - } - /** * Runs the given function asynchronously if and only if currently connected. Suppresses any * RemoteException thrown during execution. diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index eca6036ebf8e..d1d9c0e3a285 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -3282,7 +3282,7 @@ class StorageManagerService extends IStorageManager.Stub final UserManagerInternal umInternal = LocalServices.getService(UserManagerInternal.class); - for (UserInfo user : um.getUsers(false /* includeDying */)) { + for (UserInfo user : um.getUsers()) { final int flags; if (umInternal.isUserUnlockingOrUnlocked(user.id)) { flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE; diff --git a/services/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java index 1496e926b95b..84d01ec3598d 100644 --- a/services/core/java/com/android/server/SystemService.java +++ b/services/core/java/com/android/server/SystemService.java @@ -23,6 +23,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.SystemApi.Client; +import android.annotation.UserIdInt; import android.app.ActivityThread; import android.content.Context; import android.content.pm.UserInfo; @@ -131,45 +132,89 @@ public abstract class SystemService { */ @SystemApi(client = Client.SYSTEM_SERVER) public static final class TargetUser { - @NonNull - private final UserInfo mUserInfo; + + // NOTE: attributes below must be immutable while ther user is running (i.e., from the + // moment it's started until after it's shutdown). + private final @UserIdInt int mUserId; + private final boolean mFull; + private final boolean mManagedProfile; + private final boolean mPreCreated; /** @hide */ public TargetUser(@NonNull UserInfo userInfo) { - mUserInfo = userInfo; + mUserId = userInfo.id; + mFull = userInfo.isFull(); + mManagedProfile = userInfo.isManagedProfile(); + mPreCreated = userInfo.preCreated; } /** - * @return The information about the user. <b>NOTE: </b> this is a "live" object - * referenced by {@link UserManagerService} and hence should not be modified. + * Checks if the target user is {@link UserInfo#isFull() full}. * * @hide */ - @NonNull - public UserInfo getUserInfo() { - return mUserInfo; + public boolean isFull() { + return mFull; + } + + /** + * Checks if the target user is a managed profile. + * + * @hide + */ + public boolean isManagedProfile() { + return mManagedProfile; + } + + /** + * Checks if the target user is a pre-created user. + * + * @hide + */ + public boolean isPreCreated() { + return mPreCreated; } /** - * @return the target {@link UserHandle}. + * Gets the target user's {@link UserHandle}. */ @NonNull public UserHandle getUserHandle() { - return mUserInfo.getUserHandle(); + return UserHandle.of(mUserId); } /** - * @return the integer user id + * Gets the target user's id. * * @hide */ - public int getUserIdentifier() { - return mUserInfo.id; + public @UserIdInt int getUserIdentifier() { + return mUserId; } @Override public String toString() { - return Integer.toString(getUserIdentifier()); + return Integer.toString(mUserId); + } + + /** + * @hide + */ + public void dump(@NonNull StringBuilder builder) { + builder.append(getUserIdentifier()); + + if (!isFull() && !isManagedProfile()) return; + + builder.append('('); + boolean addComma = false; + if (isFull()) { + builder.append("full"); + } + if (isManagedProfile()) { + if (addComma) builder.append(','); + builder.append("mp"); + } + builder.append(')'); } } diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java index 74bb7d7e90f1..df966c1ea6ac 100644 --- a/services/core/java/com/android/server/SystemServiceManager.java +++ b/services/core/java/com/android/server/SystemServiceManager.java @@ -27,7 +27,10 @@ import android.os.UserHandle; import android.os.UserManagerInternal; import android.util.ArrayMap; import android.util.Slog; +import android.util.SparseArray; +import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.Preconditions; import com.android.server.SystemService.TargetUser; import com.android.server.utils.TimingsTraceAndSlog; @@ -74,6 +77,13 @@ public class SystemServiceManager { private UserManagerInternal mUserManagerInternal; + /** + * Map of started {@link TargetUser TargetUsers} by user id; users are added on start and + * removed after they're completely shut down. + */ + @GuardedBy("mTargetUsers") + private final SparseArray<TargetUser> mTargetUsers = new SparseArray<>(); + SystemServiceManager(Context context) { mContext = context; } @@ -240,21 +250,26 @@ public class SystemServiceManager { mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); } - private @NonNull UserInfo getUserInfo(@UserIdInt int userHandle) { - if (mUserManagerInternal == null) { - throw new IllegalStateException("mUserManagerInternal not set yet"); + private @NonNull TargetUser getTargetUser(@UserIdInt int userHandle) { + final TargetUser targetUser; + synchronized (mTargetUsers) { + targetUser = mTargetUsers.get(userHandle); } - final UserInfo userInfo = mUserManagerInternal.getUserInfo(userHandle); - if (userInfo == null) { - throw new IllegalStateException("No UserInfo for " + userHandle); - } - return userInfo; + Preconditions.checkState(targetUser != null, "No TargetUser for " + userHandle); + return targetUser; } /** * Starts the given user. */ public void startUser(final @NonNull TimingsTraceAndSlog t, final @UserIdInt int userHandle) { + // Create cached TargetUser + final UserInfo userInfo = mUserManagerInternal.getUserInfo(userHandle); + Preconditions.checkState(userInfo != null, "No UserInfo for " + userHandle); + synchronized (mTargetUsers) { + mTargetUsers.put(userHandle, new TargetUser(userInfo)); + } + onUser(t, START, userHandle); } @@ -291,6 +306,11 @@ public class SystemServiceManager { */ public void cleanupUser(final @UserIdInt int userHandle) { onUser(CLEANUP, userHandle); + + // Remove cached TargetUser + synchronized (mTargetUsers) { + mTargetUsers.remove(userHandle); + } } private void onUser(@NonNull String onWhat, @UserIdInt int userHandle) { @@ -306,9 +326,9 @@ public class SystemServiceManager { @UserIdInt int curUserId, @UserIdInt int prevUserId) { t.traceBegin("ssm." + onWhat + "User-" + curUserId); Slog.i(TAG, "Calling on" + onWhat + "User " + curUserId); - final TargetUser curUser = new TargetUser(getUserInfo(curUserId)); + final TargetUser curUser = getTargetUser(curUserId); final TargetUser prevUser = prevUserId == UserHandle.USER_NULL ? null - : new TargetUser(getUserInfo(prevUserId)); + : getTargetUser(prevUserId); final int serviceLen = mServices.size(); for (int i = 0; i < serviceLen; i++) { final SystemService service = mServices.get(i); @@ -437,7 +457,7 @@ public class SystemServiceManager { */ public void dump() { StringBuilder builder = new StringBuilder(); - builder.append("Current phase: ").append(mCurrentPhase).append("\n"); + builder.append("Current phase: ").append(mCurrentPhase).append('\n'); builder.append("Services:\n"); final int startedLen = mServices.size(); for (int i = 0; i < startedLen; i++) { @@ -447,6 +467,14 @@ public class SystemServiceManager { .append("\n"); } + builder.append("Target users: "); + final int targetUsersSize = mTargetUsers.size(); + for (int i = 0; i < targetUsersSize; i++) { + mTargetUsers.valueAt(i).dump(builder); + if (i != targetUsersSize - 1) builder.append(','); + } + builder.append('\n'); + Slog.e(TAG, builder.toString()); } } diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index b83aa4fb4d86..6328cb60cf73 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -493,6 +493,8 @@ public final class ActiveServices { } ServiceRecord r = res.record; + setFgsRestrictionLocked(callingPackage, callingPid, callingUid, service, r, + allowBackgroundActivityStarts); if (!mAm.mUserController.exists(r.userId)) { Slog.w(TAG, "Trying to start service with non-existent user! " + r.userId); @@ -516,6 +518,21 @@ public final class ActiveServices { forcedStandby = true; } + if (fgRequired) { + if (!r.mAllowStartForeground) { + if (!r.mLoggedInfoAllowStartForeground) { + Slog.wtf(TAG, "Background started FGS " + r.mInfoAllowStartForeground); + r.mLoggedInfoAllowStartForeground = true; + } + if (mAm.mConstants.mFlagFgsStartRestrictionEnabled) { + Slog.w(TAG, "startForegroundService() not allowed due to " + + " mAllowStartForeground false: service " + + r.shortInstanceName); + forcedStandby = true; + } + } + } + // If this is a direct-to-foreground start, make sure it is allowed as per the app op. boolean forceSilentAbort = false; if (fgRequired) { @@ -688,14 +705,10 @@ public final class ActiveServices { "Not potential delay (user " + r.userId + " not started): " + r); } } - if (allowBackgroundActivityStarts) { r.allowBgActivityStartsOnServiceStart(); } ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting); - - setFgsRestrictionLocked(callingPackage, callingPid, - callingUid, service, r, allowBackgroundActivityStarts); return cmp; } @@ -1422,8 +1435,8 @@ public final class ActiveServices { if (mAm.mConstants.mFlagFgsStartRestrictionEnabled) { Slog.w(TAG, "Service.startForeground() not allowed due to " - + " mAllowStartForeground false: service " - + r.shortInstanceName); + + "mAllowStartForeground false: service " + + r.shortInstanceName); updateServiceForegroundLocked(r.app, true); ignoreForeground = true; } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index f250647d7711..3e600b793385 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -98,7 +98,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESS_OBSERVERS; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE; -import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_WHITELISTS; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BACKUP; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BROADCAST; @@ -146,7 +145,6 @@ import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityManager.StackInfo; import android.app.ActivityManagerInternal; -import android.app.ActivityManagerProto; import android.app.ActivityThread; import android.app.AppGlobals; import android.app.AppOpsManager; @@ -176,7 +174,6 @@ import android.app.PendingIntent; import android.app.ProcessMemoryState; import android.app.ProfilerInfo; import android.app.WaitResult; -import android.app.backup.BackupManager; import android.app.backup.BackupManager.OperationType; import android.app.backup.IBackupManager; import android.app.usage.UsageEvents; @@ -349,7 +346,6 @@ import com.android.server.SystemServiceManager; import com.android.server.ThreadPriorityBooster; import com.android.server.UserspaceRebootLogger; import com.android.server.Watchdog; -import com.android.server.am.ActivityManagerServiceDumpProcessesProto.UidObserverRegistrationProto; import com.android.server.appop.AppOpsService; import com.android.server.compat.PlatformCompat; import com.android.server.contentcapture.ContentCaptureManagerInternal; @@ -490,9 +486,6 @@ public class ActivityManagerService extends IActivityManager.Stub // as one line, but close enough for now. static final int RESERVED_BYTES_PER_LOGCAT_LINE = 100; - /** If a UID observer takes more than this long, send a WTF. */ - private static final int SLOW_UID_OBSERVER_THRESHOLD_MS = 20; - // Necessary ApplicationInfo flags to mark an app as persistent static final int PERSISTENT_MASK = ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT; @@ -644,9 +637,6 @@ public class ActivityManagerService extends IActivityManager.Stub @VisibleForTesting long mWaitForNetworkTimeoutMs; - /** Total # of UID change events dispatched, shown in dumpsys. */ - int mUidChangeDispatchCount; - /** * Uids of apps with current active camera sessions. Access synchronized on * the IntArray instance itself, and no other locks must be acquired while that @@ -1014,12 +1004,6 @@ public class ActivityManagerService extends IActivityManager.Stub }; /** - * This is for verifying the UID report flow. - */ - static final boolean VALIDATE_UID_STATES = true; - final ActiveUids mValidateUids = new ActiveUids(this, false /* postChangesToAtm */); - - /** * Fingerprints (hashCode()) of stack traces that we've * already logged DropBox entries for. Guarded by itself. If * something (rogue user app) forces this over @@ -1399,69 +1383,6 @@ public class ActivityManagerService extends IActivityManager.Stub int foregroundServiceTypes; } - static final class UidObserverRegistration { - final int uid; - final String pkg; - final int which; - final int cutpoint; - - /** - * Total # of callback calls that took more than {@link #SLOW_UID_OBSERVER_THRESHOLD_MS}. - * We show it in dumpsys. - */ - int mSlowDispatchCount; - - /** Max time it took for each dispatch. */ - int mMaxDispatchTime; - - final SparseIntArray lastProcStates; - - // Please keep the enum lists in sync - private static int[] ORIG_ENUMS = new int[]{ - ActivityManager.UID_OBSERVER_IDLE, - ActivityManager.UID_OBSERVER_ACTIVE, - ActivityManager.UID_OBSERVER_GONE, - ActivityManager.UID_OBSERVER_PROCSTATE, - }; - private static int[] PROTO_ENUMS = new int[]{ - ActivityManagerProto.UID_OBSERVER_FLAG_IDLE, - ActivityManagerProto.UID_OBSERVER_FLAG_ACTIVE, - ActivityManagerProto.UID_OBSERVER_FLAG_GONE, - ActivityManagerProto.UID_OBSERVER_FLAG_PROCSTATE, - }; - - UidObserverRegistration(int _uid, String _pkg, int _which, int _cutpoint) { - uid = _uid; - pkg = _pkg; - which = _which; - cutpoint = _cutpoint; - if (cutpoint >= ActivityManager.MIN_PROCESS_STATE) { - lastProcStates = new SparseIntArray(); - } else { - lastProcStates = null; - } - } - - void dumpDebug(ProtoOutputStream proto, long fieldId) { - final long token = proto.start(fieldId); - proto.write(UidObserverRegistrationProto.UID, uid); - proto.write(UidObserverRegistrationProto.PACKAGE, pkg); - ProtoUtils.writeBitWiseFlagsToProtoEnum(proto, UidObserverRegistrationProto.FLAGS, - which, ORIG_ENUMS, PROTO_ENUMS); - proto.write(UidObserverRegistrationProto.CUT_POINT, cutpoint); - if (lastProcStates != null) { - final int NI = lastProcStates.size(); - for (int i=0; i<NI; i++) { - final long pToken = proto.start(UidObserverRegistrationProto.LAST_PROC_STATES); - proto.write(UidObserverRegistrationProto.ProcState.UID, lastProcStates.keyAt(i)); - proto.write(UidObserverRegistrationProto.ProcState.STATE, lastProcStates.valueAt(i)); - proto.end(pToken); - } - } - proto.end(token); - } - } - // TODO: Move below 4 members and code to ProcessList final RemoteCallbackList<IProcessObserver> mProcessObservers = new RemoteCallbackList<>(); ProcessChangeItem[] mActiveProcessChanges = new ProcessChangeItem[5]; @@ -1469,12 +1390,6 @@ public class ActivityManagerService extends IActivityManager.Stub final ArrayList<ProcessChangeItem> mPendingProcessChanges = new ArrayList<>(); final ArrayList<ProcessChangeItem> mAvailProcessChanges = new ArrayList<>(); - final RemoteCallbackList<IUidObserver> mUidObservers = new RemoteCallbackList<>(); - UidRecord.ChangeItem[] mActiveUidChanges = new UidRecord.ChangeItem[5]; - - final ArrayList<UidRecord.ChangeItem> mPendingUidChanges = new ArrayList<>(); - final ArrayList<UidRecord.ChangeItem> mAvailUidChanges = new ArrayList<>(); - OomAdjObserver mCurOomAdjObserver; int mCurOomAdjUid; @@ -1525,6 +1440,8 @@ public class ActivityManagerService extends IActivityManager.Stub public final ActivityManagerInternal mInternal; final ActivityThread mSystemThread; + final UidObserverController mUidObserverController; + private final class AppDeathRecipient implements IBinder.DeathRecipient { final ProcessRecord mApp; final int mPid; @@ -1570,7 +1487,6 @@ public class ActivityManagerService extends IActivityManager.Stub static final int NOTIFY_CLEARTEXT_NETWORK_MSG = 49; static final int POST_DUMP_HEAP_NOTIFICATION_MSG = 50; static final int ABORT_DUMPHEAP_MSG = 51; - static final int DISPATCH_UIDS_CHANGED_UI_MSG = 53; static final int SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG = 56; static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG = 57; static final int IDLE_UIDS_MSG = 58; @@ -1699,17 +1615,14 @@ public class ActivityManagerService extends IActivityManager.Stub break; } case DISPATCH_PROCESS_DIED_UI_MSG: { + if (false) { // DO NOT SUBMIT WITH TRUE + maybeTriggerWatchdog(); + } final int pid = msg.arg1; final int uid = msg.arg2; dispatchProcessDied(pid, uid); break; } - case DISPATCH_UIDS_CHANGED_UI_MSG: { - if (false) { // DO NOT SUBMIT WITH TRUE - maybeTriggerWatchdog(); - } - dispatchUidsChanged(); - } break; case DISPATCH_OOM_ADJ_OBSERVER_MSG: { dispatchOomAdjObserver((String) msg.obj); } break; @@ -1795,12 +1708,10 @@ public class ActivityManagerService extends IActivityManager.Stub } } break; case CHECK_EXCESSIVE_POWER_USE_MSG: { - synchronized (ActivityManagerService.this) { - checkExcessivePowerUsageLocked(); - removeMessages(CHECK_EXCESSIVE_POWER_USE_MSG); - Message nmsg = obtainMessage(CHECK_EXCESSIVE_POWER_USE_MSG); - sendMessageDelayed(nmsg, mConstants.POWER_CHECK_INTERVAL); - } + checkExcessivePowerUsage(); + removeMessages(CHECK_EXCESSIVE_POWER_USE_MSG); + Message nmsg = obtainMessage(CHECK_EXCESSIVE_POWER_USE_MSG); + sendMessageDelayed(nmsg, mConstants.POWER_CHECK_INTERVAL); } break; case REPORT_MEM_USAGE_MSG: { final ArrayList<ProcessMemInfo> memInfos = (ArrayList<ProcessMemInfo>)msg.obj; @@ -2511,6 +2422,7 @@ public class ActivityManagerService extends IActivityManager.Stub mConstants = hasHandlerThread ? new ActivityManagerConstants(mContext, this, mHandler) : null; final ActiveUids activeUids = new ActiveUids(this, false /* postChangesToAtm */); + mUidObserverController = new UidObserverController(this); mPlatformCompat = null; mProcessList = injector.getProcessList(this); mProcessList.init(this, activeUids, mPlatformCompat); @@ -2606,6 +2518,7 @@ public class ActivityManagerService extends IActivityManager.Stub mCpHelper = new ContentProviderHelper(this, true); mPackageWatchdog = PackageWatchdog.getInstance(mUiContext); mAppErrors = new AppErrors(mUiContext, this, mPackageWatchdog); + mUidObserverController = new UidObserverController(this); final File systemDir = SystemServiceManager.ensureSystemDir(); @@ -3422,153 +3335,6 @@ public class ActivityManagerService extends IActivityManager.Stub mProcessObservers.finishBroadcast(); } - @VisibleForTesting - void dispatchUidsChanged() { - int N; - synchronized (this) { - N = mPendingUidChanges.size(); - if (mActiveUidChanges.length < N) { - mActiveUidChanges = new UidRecord.ChangeItem[N]; - } - for (int i=0; i<N; i++) { - final UidRecord.ChangeItem change = mPendingUidChanges.get(i); - mActiveUidChanges[i] = change; - if (change.uidRecord != null) { - change.uidRecord.pendingChange = null; - change.uidRecord = null; - } - } - mPendingUidChanges.clear(); - if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, - "*** Delivering " + N + " uid changes"); - } - - mUidChangeDispatchCount += N; - int i = mUidObservers.beginBroadcast(); - while (i > 0) { - i--; - dispatchUidsChangedForObserver(mUidObservers.getBroadcastItem(i), - (UidObserverRegistration) mUidObservers.getBroadcastCookie(i), N); - } - mUidObservers.finishBroadcast(); - - if (VALIDATE_UID_STATES && mUidObservers.getRegisteredCallbackCount() > 0) { - for (int j = 0; j < N; ++j) { - final UidRecord.ChangeItem item = mActiveUidChanges[j]; - if ((item.change & UidRecord.CHANGE_GONE) != 0) { - mValidateUids.remove(item.uid); - } else { - UidRecord validateUid = mValidateUids.get(item.uid); - if (validateUid == null) { - validateUid = new UidRecord(item.uid); - mValidateUids.put(item.uid, validateUid); - } - if ((item.change & UidRecord.CHANGE_IDLE) != 0) { - validateUid.idle = true; - } else if ((item.change & UidRecord.CHANGE_ACTIVE) != 0) { - validateUid.idle = false; - } - validateUid.setCurProcState(validateUid.setProcState = item.processState); - validateUid.curCapability = validateUid.setCapability = item.capability; - validateUid.lastDispatchedProcStateSeq = item.procStateSeq; - } - } - } - - synchronized (this) { - for (int j = 0; j < N; j++) { - mAvailUidChanges.add(mActiveUidChanges[j]); - } - } - } - - private void dispatchUidsChangedForObserver(IUidObserver observer, - UidObserverRegistration reg, int changesSize) { - if (observer == null) { - return; - } - try { - for (int j = 0; j < changesSize; j++) { - UidRecord.ChangeItem item = mActiveUidChanges[j]; - final int change = item.change; - if (change == UidRecord.CHANGE_PROCSTATE && - (reg.which & ActivityManager.UID_OBSERVER_PROCSTATE) == 0) { - // No-op common case: no significant change, the observer is not - // interested in all proc state changes. - continue; - } - final long start = SystemClock.uptimeMillis(); - if ((change & UidRecord.CHANGE_IDLE) != 0) { - if ((reg.which & ActivityManager.UID_OBSERVER_IDLE) != 0) { - if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, - "UID idle uid=" + item.uid); - observer.onUidIdle(item.uid, item.ephemeral); - } - } else if ((change & UidRecord.CHANGE_ACTIVE) != 0) { - if ((reg.which & ActivityManager.UID_OBSERVER_ACTIVE) != 0) { - if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, - "UID active uid=" + item.uid); - observer.onUidActive(item.uid); - } - } - if ((reg.which & ActivityManager.UID_OBSERVER_CACHED) != 0) { - if ((change & UidRecord.CHANGE_CACHED) != 0) { - if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, - "UID cached uid=" + item.uid); - observer.onUidCachedChanged(item.uid, true); - } else if ((change & UidRecord.CHANGE_UNCACHED) != 0) { - if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, - "UID active uid=" + item.uid); - observer.onUidCachedChanged(item.uid, false); - } - } - if ((change & UidRecord.CHANGE_GONE) != 0) { - if ((reg.which & ActivityManager.UID_OBSERVER_GONE) != 0) { - if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, - "UID gone uid=" + item.uid); - observer.onUidGone(item.uid, item.ephemeral); - } - if (reg.lastProcStates != null) { - reg.lastProcStates.delete(item.uid); - } - } else { - if ((reg.which & ActivityManager.UID_OBSERVER_PROCSTATE) != 0) { - if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, - "UID CHANGED uid=" + item.uid - + ": " + item.processState + ": " + item.capability); - boolean doReport = true; - if (reg.cutpoint >= ActivityManager.MIN_PROCESS_STATE) { - final int lastState = reg.lastProcStates.get(item.uid, - ActivityManager.PROCESS_STATE_UNKNOWN); - if (lastState != ActivityManager.PROCESS_STATE_UNKNOWN) { - final boolean lastAboveCut = lastState <= reg.cutpoint; - final boolean newAboveCut = item.processState <= reg.cutpoint; - doReport = lastAboveCut != newAboveCut; - } else { - doReport = item.processState != PROCESS_STATE_NONEXISTENT; - } - } - if (doReport) { - if (reg.lastProcStates != null) { - reg.lastProcStates.put(item.uid, item.processState); - } - observer.onUidStateChanged(item.uid, item.processState, - item.procStateSeq, item.capability); - } - } - } - final int duration = (int) (SystemClock.uptimeMillis() - start); - if (reg.mMaxDispatchTime < duration) { - reg.mMaxDispatchTime = duration; - } - if (duration >= SLOW_UID_OBSERVER_THRESHOLD_MS) { - reg.mSlowDispatchCount++; - } - } - } catch (RemoteException e) { - } - } - void dispatchOomAdjObserver(String msg) { OomAdjObserver observer; synchronized (this) { @@ -4609,10 +4375,12 @@ public class ActivityManagerService extends IActivityManager.Stub proc.lastMemInfoTime = SystemClock.uptimeMillis(); if (proc.thread != null && proc.setAdj == oomAdj) { // Record this for posterity if the process has been stable. - proc.baseProcessTracker.addPss(infos[i].getTotalPss(), - infos[i].getTotalUss(), infos[i].getTotalRss(), false, - ProcessStats.ADD_PSS_EXTERNAL_SLOW, endTime - startTime, - proc.pkgList.mPkgList); + synchronized (mProcessStats.mLock) { + proc.baseProcessTracker.addPss(infos[i].getTotalPss(), + infos[i].getTotalUss(), infos[i].getTotalRss(), false, + ProcessStats.ADD_PSS_EXTERNAL_SLOW, endTime - startTime, + proc.pkgList.mPkgList); + } for (int ipkg = proc.pkgList.size() - 1; ipkg >= 0; ipkg--) { ProcessStats.ProcessStateHolder holder = proc.pkgList.valueAt(ipkg); FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_MEMORY_STAT_REPORTED, @@ -4669,8 +4437,11 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (this) { if (proc.thread != null && proc.setAdj == oomAdj) { // Record this for posterity if the process has been stable. - proc.baseProcessTracker.addPss(pss[i], tmpUss[0], tmpUss[2], false, - ProcessStats.ADD_PSS_EXTERNAL, endTime-startTime, proc.pkgList.mPkgList); + synchronized (mProcessStats.mLock) { + proc.baseProcessTracker.addPss(pss[i], tmpUss[0], tmpUss[2], false, + ProcessStats.ADD_PSS_EXTERNAL, endTime - startTime, + proc.pkgList.mPkgList); + } for (int ipkg = proc.pkgList.size() - 1; ipkg >= 0; ipkg--) { ProcessStats.ProcessStateHolder holder = proc.pkgList.valueAt(ipkg); FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_MEMORY_STAT_REPORTED, @@ -7500,15 +7271,15 @@ public class ActivityManagerService extends IActivityManager.Stub "registerUidObserver"); } synchronized (this) { - mUidObservers.register(observer, new UidObserverRegistration(Binder.getCallingUid(), - callingPackage, which, cutpoint)); + mUidObserverController.register(observer, which, cutpoint, callingPackage, + Binder.getCallingUid()); } } @Override public void unregisterUidObserver(IUidObserver observer) { synchronized (this) { - mUidObservers.unregister(observer); + mUidObserverController.unregister(observer); } } @@ -10127,9 +9898,9 @@ public class ActivityManagerService extends IActivityManager.Stub } if (dumpAll) { - if (mValidateUids.size() > 0) { - if (dumpUids(pw, dumpPackage, dumpAppId, mValidateUids, "UID validation:", - needSep)) { + if (mUidObserverController.mValidateUids.size() > 0) { + if (dumpUids(pw, dumpPackage, dumpAppId, mUidObserverController.mValidateUids, + "UID validation:", needSep)) { needSep = true; } } @@ -10261,45 +10032,8 @@ public class ActivityManagerService extends IActivityManager.Stub } } if (dumpAll) { - final int NI = mUidObservers.getRegisteredCallbackCount(); - boolean printed = false; - for (int i=0; i<NI; i++) { - final UidObserverRegistration reg = (UidObserverRegistration) - mUidObservers.getRegisteredCallbackCookie(i); - if (dumpPackage == null || dumpPackage.equals(reg.pkg)) { - if (!printed) { - pw.println(" mUidObservers:"); - printed = true; - } - pw.print(" "); UserHandle.formatUid(pw, reg.uid); - pw.print(" "); pw.print(reg.pkg); - final IUidObserver observer = mUidObservers.getRegisteredCallbackItem(i); - pw.print(" "); pw.print(observer.getClass().getTypeName()); pw.print(":"); - if ((reg.which&ActivityManager.UID_OBSERVER_IDLE) != 0) { - pw.print(" IDLE"); - } - if ((reg.which&ActivityManager.UID_OBSERVER_ACTIVE) != 0) { - pw.print(" ACT" ); - } - if ((reg.which&ActivityManager.UID_OBSERVER_GONE) != 0) { - pw.print(" GONE"); - } - if ((reg.which&ActivityManager.UID_OBSERVER_PROCSTATE) != 0) { - pw.print(" STATE"); - pw.print(" (cut="); pw.print(reg.cutpoint); - pw.print(")"); - } - pw.println(); - if (reg.lastProcStates != null) { - final int NJ = reg.lastProcStates.size(); - for (int j=0; j<NJ; j++) { - pw.print(" Last "); - UserHandle.formatUid(pw, reg.lastProcStates.keyAt(j)); - pw.print(": "); pw.println(reg.lastProcStates.valueAt(j)); - } - } - } - } + mUidObserverController.dump(pw, dumpPackage); + pw.println(" mDeviceIdleWhitelist=" + Arrays.toString(mDeviceIdleWhitelist)); pw.println(" mDeviceIdleExceptIdleWhitelist=" + Arrays.toString(mDeviceIdleExceptIdleWhitelist)); @@ -10427,25 +10161,6 @@ public class ActivityManagerService extends IActivityManager.Stub pw.print(" mLowRamSinceLastIdle="); TimeUtils.formatDuration(getLowRamTimeSinceIdle(now), pw); pw.println(); - pw.println(); - pw.print(" mUidChangeDispatchCount="); - pw.print(mUidChangeDispatchCount); - pw.println(); - - pw.println(" Slow UID dispatches:"); - final int N = mUidObservers.beginBroadcast(); - for (int i = 0; i < N; i++) { - UidObserverRegistration r = - (UidObserverRegistration) mUidObservers.getBroadcastCookie(i); - pw.print(" "); - pw.print(mUidObservers.getBroadcastItem(i).getClass().getTypeName()); - pw.print(": "); - pw.print(r.mSlowDispatchCount); - pw.print(" / Max "); - pw.print(r.mMaxDispatchTime); - pw.println("ms"); - } - mUidObservers.finishBroadcast(); pw.println(); pw.println(" ServiceManager statistics:"); @@ -10513,8 +10228,8 @@ public class ActivityManagerService extends IActivityManager.Stub uidRec.dumpDebug(proto, ActivityManagerServiceDumpProcessesProto.ACTIVE_UIDS); } - for (int i = 0; i < mValidateUids.size(); i++) { - UidRecord uidRec = mValidateUids.valueAt(i); + for (int i = 0; i < mUidObserverController.mValidateUids.size(); i++) { + UidRecord uidRec = mUidObserverController.mValidateUids.valueAt(i); if (dumpPackage != null && UserHandle.getAppId(uidRec.uid) != whichAppId) { continue; } @@ -10599,14 +10314,7 @@ public class ActivityManagerService extends IActivityManager.Stub ActivityManagerServiceDumpProcessesProto.USER_CONTROLLER); } - final int NI = mUidObservers.getRegisteredCallbackCount(); - for (int i=0; i<NI; i++) { - final UidObserverRegistration reg = (UidObserverRegistration) - mUidObservers.getRegisteredCallbackCookie(i); - if (dumpPackage == null || dumpPackage.equals(reg.pkg)) { - reg.dumpDebug(proto, ActivityManagerServiceDumpProcessesProto.UID_OBSERVERS); - } - } + mUidObserverController.dumpDebug(proto, dumpPackage); for (int v : mDeviceIdleWhitelist) { proto.write(ActivityManagerServiceDumpProcessesProto.DEVICE_IDLE_WHITELIST, v); @@ -12107,8 +11815,10 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (this) { if (r.thread != null && oomAdj == r.getSetAdjWithServices()) { // Record this for posterity if the process has been stable. - r.baseProcessTracker.addPss(myTotalPss, myTotalUss, myTotalRss, true, - reportType, endTime-startTime, r.pkgList.mPkgList); + synchronized (mProcessStats.mLock) { + r.baseProcessTracker.addPss(myTotalPss, myTotalUss, myTotalRss, true, + reportType, endTime - startTime, r.pkgList.mPkgList); + } for (int ipkg = r.pkgList.size() - 1; ipkg >= 0; ipkg--) { ProcessStats.ProcessStateHolder holder = r.pkgList.valueAt(ipkg); FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_MEMORY_STAT_REPORTED, @@ -12713,8 +12423,10 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (this) { if (r.thread != null && oomAdj == r.getSetAdjWithServices()) { // Record this for posterity if the process has been stable. - r.baseProcessTracker.addPss(myTotalPss, myTotalUss, myTotalRss, true, - reportType, endTime-startTime, r.pkgList.mPkgList); + synchronized (mProcessStats.mLock) { + r.baseProcessTracker.addPss(myTotalPss, myTotalUss, myTotalRss, true, + reportType, endTime - startTime, r.pkgList.mPkgList); + } for (int ipkg = r.pkgList.size() - 1; ipkg >= 0; ipkg--) { ProcessStats.ProcessStateHolder holder = r.pkgList.valueAt(ipkg); FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_MEMORY_STAT_REPORTED, @@ -15927,8 +15639,10 @@ public class ActivityManagerService extends IActivityManager.Stub EventLogTags.writeAmPss(proc.pid, proc.uid, proc.processName, pss * 1024, uss * 1024, swapPss * 1024, rss * 1024, statType, procState, pssDuration); proc.lastPssTime = now; - proc.baseProcessTracker.addPss( - pss, uss, rss, true, statType, pssDuration, proc.pkgList.mPkgList); + synchronized (mProcessStats.mLock) { + proc.baseProcessTracker.addPss( + pss, uss, rss, true, statType, pssDuration, proc.pkgList.mPkgList); + } for (int ipkg = proc.pkgList.mPkgList.size() - 1; ipkg >= 0; ipkg--) { ProcessStats.ProcessStateHolder holder = proc.pkgList.valueAt(ipkg); FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_MEMORY_STAT_REPORTED, @@ -16230,182 +15944,94 @@ public class ActivityManagerService extends IActivityManager.Stub } } - final void checkExcessivePowerUsageLocked() { + private void checkExcessivePowerUsage() { updateCpuStatsNow(); - BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics(); - boolean doCpuKills = true; - if (mLastPowerCheckUptime == 0) { - doCpuKills = false; - } - final long curUptime = SystemClock.uptimeMillis(); - final long uptimeSince = curUptime - mLastPowerCheckUptime; - mLastPowerCheckUptime = curUptime; - int i = mProcessList.mLruProcesses.size(); - while (i > 0) { - i--; - ProcessRecord app = mProcessList.mLruProcesses.get(i); - if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) { - if (app.lastCpuTime <= 0) { - continue; - } - long cputimeUsed = app.curCpuTime - app.lastCpuTime; - if (DEBUG_POWER) { - StringBuilder sb = new StringBuilder(128); - sb.append("CPU for "); - app.toShortString(sb); - sb.append(": over "); - TimeUtils.formatDuration(uptimeSince, sb); - sb.append(" used "); - TimeUtils.formatDuration(cputimeUsed, sb); - sb.append(" ("); - sb.append((cputimeUsed*100)/uptimeSince); - sb.append("%)"); - Slog.i(TAG_POWER, sb.toString()); - } - // If the process has used too much CPU over the last duration, the - // user probably doesn't want this, so kill! - if (doCpuKills && uptimeSince > 0) { - // What is the limit for this process? - int cpuLimit; - long checkDur = curUptime - app.getWhenUnimportant(); - if (checkDur <= mConstants.POWER_CHECK_INTERVAL) { - cpuLimit = mConstants.POWER_CHECK_MAX_CPU_1; - } else if (checkDur <= (mConstants.POWER_CHECK_INTERVAL*2) - || app.setProcState <= ActivityManager.PROCESS_STATE_HOME) { - cpuLimit = mConstants.POWER_CHECK_MAX_CPU_2; - } else if (checkDur <= (mConstants.POWER_CHECK_INTERVAL*3)) { - cpuLimit = mConstants.POWER_CHECK_MAX_CPU_3; - } else { - cpuLimit = mConstants.POWER_CHECK_MAX_CPU_4; + synchronized (this) { + BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics(); + boolean doCpuKills = true; + if (mLastPowerCheckUptime == 0) { + doCpuKills = false; + } + final long curUptime = SystemClock.uptimeMillis(); + final long uptimeSince = curUptime - mLastPowerCheckUptime; + mLastPowerCheckUptime = curUptime; + int i = mProcessList.mLruProcesses.size(); + while (i > 0) { + i--; + ProcessRecord app = mProcessList.mLruProcesses.get(i); + if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) { + if (app.lastCpuTime <= 0) { + continue; + } + long cputimeUsed = app.curCpuTime - app.lastCpuTime; + if (DEBUG_POWER) { + StringBuilder sb = new StringBuilder(128); + sb.append("CPU for "); + app.toShortString(sb); + sb.append(": over "); + TimeUtils.formatDuration(uptimeSince, sb); + sb.append(" used "); + TimeUtils.formatDuration(cputimeUsed, sb); + sb.append(" ("); + sb.append((cputimeUsed * 100) / uptimeSince); + sb.append("%)"); + Slog.i(TAG_POWER, sb.toString()); } - if (((cputimeUsed*100)/uptimeSince) >= cpuLimit) { - synchronized (stats) { - stats.reportExcessiveCpuLocked(app.info.uid, app.processName, - uptimeSince, cputimeUsed); + // If the process has used too much CPU over the last duration, the + // user probably doesn't want this, so kill! + if (doCpuKills && uptimeSince > 0) { + // What is the limit for this process? + int cpuLimit; + long checkDur = curUptime - app.getWhenUnimportant(); + if (checkDur <= mConstants.POWER_CHECK_INTERVAL) { + cpuLimit = mConstants.POWER_CHECK_MAX_CPU_1; + } else if (checkDur <= (mConstants.POWER_CHECK_INTERVAL * 2) + || app.setProcState <= ActivityManager.PROCESS_STATE_HOME) { + cpuLimit = mConstants.POWER_CHECK_MAX_CPU_2; + } else if (checkDur <= (mConstants.POWER_CHECK_INTERVAL * 3)) { + cpuLimit = mConstants.POWER_CHECK_MAX_CPU_3; + } else { + cpuLimit = mConstants.POWER_CHECK_MAX_CPU_4; } - app.kill("excessive cpu " + cputimeUsed + " during " + uptimeSince - + " dur=" + checkDur + " limit=" + cpuLimit, - ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE, - ApplicationExitInfo.SUBREASON_EXCESSIVE_CPU, - true); - app.baseProcessTracker.reportExcessiveCpu(app.pkgList.mPkgList); - for (int ipkg = app.pkgList.size() - 1; ipkg >= 0; ipkg--) { - ProcessStats.ProcessStateHolder holder = app.pkgList.valueAt(ipkg); - FrameworkStatsLog.write(FrameworkStatsLog.EXCESSIVE_CPU_USAGE_REPORTED, - app.info.uid, - holder.state.getName(), - holder.state.getPackage(), - holder.appVersion); + if (((cputimeUsed * 100) / uptimeSince) >= cpuLimit) { + synchronized (stats) { + stats.reportExcessiveCpuLocked(app.info.uid, app.processName, + uptimeSince, cputimeUsed); + } + app.kill("excessive cpu " + cputimeUsed + " during " + uptimeSince + + " dur=" + checkDur + " limit=" + cpuLimit, + ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE, + ApplicationExitInfo.SUBREASON_EXCESSIVE_CPU, + true); + synchronized (mProcessStats.mLock) { + app.baseProcessTracker.reportExcessiveCpu(app.pkgList.mPkgList); + } + for (int ipkg = app.pkgList.size() - 1; ipkg >= 0; ipkg--) { + ProcessStats.ProcessStateHolder holder = app.pkgList.valueAt(ipkg); + FrameworkStatsLog.write( + FrameworkStatsLog.EXCESSIVE_CPU_USAGE_REPORTED, + app.info.uid, + holder.state.getName(), + holder.state.getPackage(), + holder.appVersion); + } } } + app.lastCpuTime = app.curCpuTime; } - app.lastCpuTime = app.curCpuTime; - } - } - } - - private boolean isEphemeralLocked(int uid) { - String packages[] = mContext.getPackageManager().getPackagesForUid(uid); - if (packages == null || packages.length != 1) { // Ephemeral apps cannot share uid - return false; - } - return getPackageManagerInternalLocked().isPackageEphemeral(UserHandle.getUserId(uid), - packages[0]); - } - - @VisibleForTesting - final void enqueueUidChangeLocked(UidRecord uidRec, int uid, int change) { - final UidRecord.ChangeItem pendingChange; - if (uidRec == null || uidRec.pendingChange == null) { - if (mPendingUidChanges.size() == 0) { - if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, - "*** Enqueueing dispatch uid changed!"); - mUiHandler.obtainMessage(DISPATCH_UIDS_CHANGED_UI_MSG).sendToTarget(); - } - final int NA = mAvailUidChanges.size(); - if (NA > 0) { - pendingChange = mAvailUidChanges.remove(NA-1); - if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, - "Retrieving available item: " + pendingChange); - } else { - pendingChange = new UidRecord.ChangeItem(); - if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, - "Allocating new item: " + pendingChange); - } - if (uidRec != null) { - uidRec.pendingChange = pendingChange; - if ((change & UidRecord.CHANGE_GONE) != 0 && !uidRec.idle) { - // If this uid is going away, and we haven't yet reported it is gone, - // then do so now. - change |= UidRecord.CHANGE_IDLE; - } - } else if (uid < 0) { - throw new IllegalArgumentException("No UidRecord or uid"); - } - pendingChange.uidRecord = uidRec; - pendingChange.uid = uidRec != null ? uidRec.uid : uid; - mPendingUidChanges.add(pendingChange); - } else { - pendingChange = uidRec.pendingChange; - // If there is no change in idle or active state, then keep whatever was pending. - if ((change & (UidRecord.CHANGE_IDLE | UidRecord.CHANGE_ACTIVE)) == 0) { - change |= (pendingChange.change & (UidRecord.CHANGE_IDLE - | UidRecord.CHANGE_ACTIVE)); - } - // If there is no change in cached or uncached state, then keep whatever was pending. - if ((change & (UidRecord.CHANGE_CACHED | UidRecord.CHANGE_UNCACHED)) == 0) { - change |= (pendingChange.change & (UidRecord.CHANGE_CACHED - | UidRecord.CHANGE_UNCACHED)); - } - // If this is a report of the UID being gone, then we shouldn't keep any previous - // report of it being active or cached. (That is, a gone uid is never active, - // and never cached.) - if ((change & UidRecord.CHANGE_GONE) != 0) { - change &= ~(UidRecord.CHANGE_ACTIVE | UidRecord.CHANGE_CACHED); - if (!uidRec.idle) { - // If this uid is going away, and we haven't yet reported it is gone, - // then do so now. - change |= UidRecord.CHANGE_IDLE; - } - } - } - pendingChange.change = change; - pendingChange.processState = uidRec != null ? uidRec.setProcState : PROCESS_STATE_NONEXISTENT; - pendingChange.capability = uidRec != null ? uidRec.setCapability : 0; - pendingChange.ephemeral = uidRec != null ? uidRec.ephemeral : isEphemeralLocked(uid); - pendingChange.procStateSeq = uidRec != null ? uidRec.curProcStateSeq : 0; - if (uidRec != null) { - uidRec.lastReportedChange = change; - uidRec.updateLastDispatchedProcStateSeq(change); - } - - // Directly update the power manager, since we sit on top of it and it is critical - // it be kept in sync (so wake locks will be held as soon as appropriate). - if (mLocalPowerManager != null) { - // TO DO: dispatch cached/uncached changes here, so we don't need to report - // all proc state changes. - if ((change & UidRecord.CHANGE_ACTIVE) != 0) { - mLocalPowerManager.uidActive(pendingChange.uid); - } - if ((change & UidRecord.CHANGE_IDLE) != 0) { - mLocalPowerManager.uidIdle(pendingChange.uid); - } - if ((change & UidRecord.CHANGE_GONE) != 0) { - mLocalPowerManager.uidGone(pendingChange.uid); - } else { - mLocalPowerManager.updateUidProcState(pendingChange.uid, - pendingChange.processState); } } } final void setProcessTrackerStateLocked(ProcessRecord proc, int memFactor, long now) { - if (proc.thread != null && proc.baseProcessTracker != null) { - final int procState = proc.getReportedProcState(); - if (procState != PROCESS_STATE_NONEXISTENT) { - proc.baseProcessTracker.setState( - procState, memFactor, now, proc.pkgList.mPkgList); + synchronized (mProcessStats.mLock) { + if (proc.thread != null && proc.baseProcessTracker != null) { + final int procState = proc.getReportedProcState(); + if (procState != PROCESS_STATE_NONEXISTENT) { + proc.baseProcessTracker.setState( + procState, memFactor, now, proc.pkgList.mPkgList); + } } } } @@ -16818,7 +16444,7 @@ public class ActivityManagerService extends IActivityManager.Stub @GuardedBy("this") final void doStopUidLocked(int uid, final UidRecord uidRec) { mServices.stopInBackgroundLocked(uid); - enqueueUidChangeLocked(uidRec, uid, UidRecord.CHANGE_IDLE); + mUidObserverController.enqueueUidChangeLocked(uidRec, uid, UidRecord.CHANGE_IDLE); } /** @@ -18479,7 +18105,8 @@ public class ActivityManagerService extends IActivityManager.Stub Slog.w(TAG_NETWORK, "Total time waited for network rules to get updated: " + totalTime + ". Uid: " + callingUid + " procStateSeq: " + procStateSeq + " UidRec: " + record - + " validateUidRec: " + mValidateUids.get(callingUid)); + + " validateUidRec: " + + mUidObserverController.mValidateUids.get(callingUid)); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index bf15f1737cfc..bad042cd3a68 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -987,7 +987,7 @@ public final class OomAdjuster { uidRec.setWhitelist = uidRec.curWhitelist; uidRec.setIdle = uidRec.idle; mService.mAtmInternal.onUidProcStateChanged(uidRec.uid, uidRec.setProcState); - mService.enqueueUidChangeLocked(uidRec, -1, uidChange); + mService.mUidObserverController.enqueueUidChangeLocked(uidRec, -1, uidChange); mService.noteUidProcessState(uidRec.uid, uidRec.getCurProcState(), uidRec.curCapability); if (uidRec.foregroundServices) { diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 5721fb7f5128..2e8660e1317a 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -2960,7 +2960,8 @@ public final class ProcessList { // No more processes using this uid, tell clients it is gone. if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, "No more processes in " + uidRecord); - mService.enqueueUidChangeLocked(uidRecord, -1, UidRecord.CHANGE_GONE); + mService.mUidObserverController.enqueueUidChangeLocked(uidRecord, -1, + UidRecord.CHANGE_GONE); EventLogTags.writeAmUidStopped(uid); mActiveUids.remove(uid); mService.noteUidProcessState(uid, ActivityManager.PROCESS_STATE_NONEXISTENT, diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index e3e13391a8b0..14bc6cbed7d7 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -1079,8 +1079,8 @@ class ProcessRecord implements WindowProcessListener { */ public void resetPackageList(ProcessStatsService tracker) { final int N = pkgList.size(); - if (baseProcessTracker != null) { - synchronized (tracker.mLock) { + synchronized (tracker.mLock) { + if (baseProcessTracker != null) { long now = SystemClock.uptimeMillis(); baseProcessTracker.setState(ProcessStats.STATE_NOTHING, tracker.getMemFactorLocked(), now, pkgList.mPkgList); @@ -1108,10 +1108,11 @@ class ProcessRecord implements WindowProcessListener { holder.state.makeActive(); } } + } else if (N != 1) { + pkgList.clear(); + pkgList.put(info.packageName, + new ProcessStats.ProcessStateHolder(info.longVersionCode)); } - } else if (N != 1) { - pkgList.clear(); - pkgList.put(info.packageName, new ProcessStats.ProcessStateHolder(info.longVersionCode)); } } diff --git a/services/core/java/com/android/server/am/UidObserverController.java b/services/core/java/com/android/server/am/UidObserverController.java new file mode 100644 index 000000000000..4c4dd8b8defa --- /dev/null +++ b/services/core/java/com/android/server/am/UidObserverController.java @@ -0,0 +1,460 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.am; + +import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; + +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS; +import static com.android.server.am.ActivityManagerService.TAG_UID_OBSERVERS; + +import android.app.ActivityManager; +import android.app.ActivityManagerProto; +import android.app.IUidObserver; +import android.os.RemoteCallbackList; +import android.os.RemoteException; +import android.os.SystemClock; +import android.os.UserHandle; +import android.util.Slog; +import android.util.SparseIntArray; +import android.util.proto.ProtoOutputStream; +import android.util.proto.ProtoUtils; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.am.ActivityManagerServiceDumpProcessesProto.UidObserverRegistrationProto; + +import java.io.PrintWriter; +import java.util.ArrayList; + +public class UidObserverController { + private final ActivityManagerService mService; + final RemoteCallbackList<IUidObserver> mUidObservers = new RemoteCallbackList<>(); + + UidRecord.ChangeItem[] mActiveUidChanges = new UidRecord.ChangeItem[5]; + final ArrayList<UidRecord.ChangeItem> mPendingUidChanges = new ArrayList<>(); + final ArrayList<UidRecord.ChangeItem> mAvailUidChanges = new ArrayList<>(); + + /** Total # of UID change events dispatched, shown in dumpsys. */ + int mUidChangeDispatchCount; + + /** If a UID observer takes more than this long, send a WTF. */ + private static final int SLOW_UID_OBSERVER_THRESHOLD_MS = 20; + + /** + * This is for verifying the UID report flow. + */ + static final boolean VALIDATE_UID_STATES = true; + final ActiveUids mValidateUids; + + UidObserverController(ActivityManagerService service) { + mService = service; + mValidateUids = new ActiveUids(mService, false /* postChangesToAtm */); + } + + @GuardedBy("mService") + void register(IUidObserver observer, int which, int cutpoint, String callingPackage, + int callingUid) { + mUidObservers.register(observer, new UidObserverRegistration(callingUid, + callingPackage, which, cutpoint)); + } + + @GuardedBy("mService") + void unregister(IUidObserver observer) { + mUidObservers.unregister(observer); + } + + @GuardedBy("mService") + final void enqueueUidChangeLocked(UidRecord uidRec, int uid, int change) { + final UidRecord.ChangeItem pendingChange; + if (uidRec == null || uidRec.pendingChange == null) { + if (mPendingUidChanges.size() == 0) { + if (DEBUG_UID_OBSERVERS) { + Slog.i(TAG_UID_OBSERVERS, "*** Enqueueing dispatch uid changed!"); + } + mService.mUiHandler.post(this::dispatchUidsChanged); + } + final int NA = mAvailUidChanges.size(); + if (NA > 0) { + pendingChange = mAvailUidChanges.remove(NA-1); + if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, + "Retrieving available item: " + pendingChange); + } else { + pendingChange = new UidRecord.ChangeItem(); + if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, + "Allocating new item: " + pendingChange); + } + if (uidRec != null) { + uidRec.pendingChange = pendingChange; + if ((change & UidRecord.CHANGE_GONE) != 0 && !uidRec.idle) { + // If this uid is going away, and we haven't yet reported it is gone, + // then do so now. + change |= UidRecord.CHANGE_IDLE; + } + } else if (uid < 0) { + throw new IllegalArgumentException("No UidRecord or uid"); + } + pendingChange.uidRecord = uidRec; + pendingChange.uid = uidRec != null ? uidRec.uid : uid; + mPendingUidChanges.add(pendingChange); + } else { + pendingChange = uidRec.pendingChange; + // If there is no change in idle or active state, then keep whatever was pending. + if ((change & (UidRecord.CHANGE_IDLE | UidRecord.CHANGE_ACTIVE)) == 0) { + change |= (pendingChange.change & (UidRecord.CHANGE_IDLE + | UidRecord.CHANGE_ACTIVE)); + } + // If there is no change in cached or uncached state, then keep whatever was pending. + if ((change & (UidRecord.CHANGE_CACHED | UidRecord.CHANGE_UNCACHED)) == 0) { + change |= (pendingChange.change & (UidRecord.CHANGE_CACHED + | UidRecord.CHANGE_UNCACHED)); + } + // If this is a report of the UID being gone, then we shouldn't keep any previous + // report of it being active or cached. (That is, a gone uid is never active, + // and never cached.) + if ((change & UidRecord.CHANGE_GONE) != 0) { + change &= ~(UidRecord.CHANGE_ACTIVE | UidRecord.CHANGE_CACHED); + if (!uidRec.idle) { + // If this uid is going away, and we haven't yet reported it is gone, + // then do so now. + change |= UidRecord.CHANGE_IDLE; + } + } + } + pendingChange.change = change; + pendingChange.processState = uidRec != null ? uidRec.setProcState : PROCESS_STATE_NONEXISTENT; + pendingChange.capability = uidRec != null ? uidRec.setCapability : 0; + pendingChange.ephemeral = uidRec != null ? uidRec.ephemeral : isEphemeralLocked(uid); + pendingChange.procStateSeq = uidRec != null ? uidRec.curProcStateSeq : 0; + if (uidRec != null) { + uidRec.lastReportedChange = change; + uidRec.updateLastDispatchedProcStateSeq(change); + } + + // Directly update the power manager, since we sit on top of it and it is critical + // it be kept in sync (so wake locks will be held as soon as appropriate). + if (mService.mLocalPowerManager != null) { + // TO DO: dispatch cached/uncached changes here, so we don't need to report + // all proc state changes. + if ((change & UidRecord.CHANGE_ACTIVE) != 0) { + mService.mLocalPowerManager.uidActive(pendingChange.uid); + } + if ((change & UidRecord.CHANGE_IDLE) != 0) { + mService.mLocalPowerManager.uidIdle(pendingChange.uid); + } + if ((change & UidRecord.CHANGE_GONE) != 0) { + mService.mLocalPowerManager.uidGone(pendingChange.uid); + } else { + mService.mLocalPowerManager.updateUidProcState(pendingChange.uid, + pendingChange.processState); + } + } + } + + @VisibleForTesting + void dispatchUidsChanged() { + int N; + synchronized (mService) { + N = mPendingUidChanges.size(); + if (mActiveUidChanges.length < N) { + mActiveUidChanges = new UidRecord.ChangeItem[N]; + } + for (int i=0; i<N; i++) { + final UidRecord.ChangeItem change = mPendingUidChanges.get(i); + mActiveUidChanges[i] = change; + if (change.uidRecord != null) { + change.uidRecord.pendingChange = null; + change.uidRecord = null; + } + } + mPendingUidChanges.clear(); + if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, + "*** Delivering " + N + " uid changes"); + } + + mUidChangeDispatchCount += N; + int i = mUidObservers.beginBroadcast(); + while (i > 0) { + i--; + dispatchUidsChangedForObserver(mUidObservers.getBroadcastItem(i), + (UidObserverRegistration) mUidObservers.getBroadcastCookie(i), N); + } + mUidObservers.finishBroadcast(); + + if (VALIDATE_UID_STATES && mUidObservers.getRegisteredCallbackCount() > 0) { + for (int j = 0; j < N; ++j) { + final UidRecord.ChangeItem item = mActiveUidChanges[j]; + if ((item.change & UidRecord.CHANGE_GONE) != 0) { + mValidateUids.remove(item.uid); + } else { + UidRecord validateUid = mValidateUids.get(item.uid); + if (validateUid == null) { + validateUid = new UidRecord(item.uid); + mValidateUids.put(item.uid, validateUid); + } + if ((item.change & UidRecord.CHANGE_IDLE) != 0) { + validateUid.idle = true; + } else if ((item.change & UidRecord.CHANGE_ACTIVE) != 0) { + validateUid.idle = false; + } + validateUid.setCurProcState(validateUid.setProcState = item.processState); + validateUid.curCapability = validateUid.setCapability = item.capability; + validateUid.lastDispatchedProcStateSeq = item.procStateSeq; + } + } + } + + synchronized (mService) { + for (int j = 0; j < N; j++) { + mAvailUidChanges.add(mActiveUidChanges[j]); + } + } + } + + private void dispatchUidsChangedForObserver(IUidObserver observer, + UidObserverRegistration reg, int changesSize) { + if (observer == null) { + return; + } + try { + for (int j = 0; j < changesSize; j++) { + UidRecord.ChangeItem item = mActiveUidChanges[j]; + final int change = item.change; + if (change == UidRecord.CHANGE_PROCSTATE && + (reg.which & ActivityManager.UID_OBSERVER_PROCSTATE) == 0) { + // No-op common case: no significant change, the observer is not + // interested in all proc state changes. + continue; + } + final long start = SystemClock.uptimeMillis(); + if ((change & UidRecord.CHANGE_IDLE) != 0) { + if ((reg.which & ActivityManager.UID_OBSERVER_IDLE) != 0) { + if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, + "UID idle uid=" + item.uid); + observer.onUidIdle(item.uid, item.ephemeral); + } + } else if ((change & UidRecord.CHANGE_ACTIVE) != 0) { + if ((reg.which & ActivityManager.UID_OBSERVER_ACTIVE) != 0) { + if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, + "UID active uid=" + item.uid); + observer.onUidActive(item.uid); + } + } + if ((reg.which & ActivityManager.UID_OBSERVER_CACHED) != 0) { + if ((change & UidRecord.CHANGE_CACHED) != 0) { + if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, + "UID cached uid=" + item.uid); + observer.onUidCachedChanged(item.uid, true); + } else if ((change & UidRecord.CHANGE_UNCACHED) != 0) { + if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, + "UID active uid=" + item.uid); + observer.onUidCachedChanged(item.uid, false); + } + } + if ((change & UidRecord.CHANGE_GONE) != 0) { + if ((reg.which & ActivityManager.UID_OBSERVER_GONE) != 0) { + if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, + "UID gone uid=" + item.uid); + observer.onUidGone(item.uid, item.ephemeral); + } + if (reg.lastProcStates != null) { + reg.lastProcStates.delete(item.uid); + } + } else { + if ((reg.which & ActivityManager.UID_OBSERVER_PROCSTATE) != 0) { + if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, + "UID CHANGED uid=" + item.uid + + ": " + item.processState + ": " + item.capability); + boolean doReport = true; + if (reg.cutpoint >= ActivityManager.MIN_PROCESS_STATE) { + final int lastState = reg.lastProcStates.get(item.uid, + ActivityManager.PROCESS_STATE_UNKNOWN); + if (lastState != ActivityManager.PROCESS_STATE_UNKNOWN) { + final boolean lastAboveCut = lastState <= reg.cutpoint; + final boolean newAboveCut = item.processState <= reg.cutpoint; + doReport = lastAboveCut != newAboveCut; + } else { + doReport = item.processState != PROCESS_STATE_NONEXISTENT; + } + } + if (doReport) { + if (reg.lastProcStates != null) { + reg.lastProcStates.put(item.uid, item.processState); + } + observer.onUidStateChanged(item.uid, item.processState, + item.procStateSeq, item.capability); + } + } + } + final int duration = (int) (SystemClock.uptimeMillis() - start); + if (reg.mMaxDispatchTime < duration) { + reg.mMaxDispatchTime = duration; + } + if (duration >= SLOW_UID_OBSERVER_THRESHOLD_MS) { + reg.mSlowDispatchCount++; + } + } + } catch (RemoteException e) { + } + } + + private boolean isEphemeralLocked(int uid) { + String packages[] = mService.mContext.getPackageManager().getPackagesForUid(uid); + if (packages == null || packages.length != 1) { // Ephemeral apps cannot share uid + return false; + } + return mService.getPackageManagerInternalLocked().isPackageEphemeral( + UserHandle.getUserId(uid), packages[0]); + } + + @GuardedBy("mService") + void dump(PrintWriter pw, String dumpPackage) { + final int NI = mUidObservers.getRegisteredCallbackCount(); + boolean printed = false; + for (int i=0; i<NI; i++) { + final UidObserverRegistration reg = (UidObserverRegistration) + mUidObservers.getRegisteredCallbackCookie(i); + if (dumpPackage == null || dumpPackage.equals(reg.pkg)) { + if (!printed) { + pw.println(" mUidObservers:"); + printed = true; + } + pw.print(" "); UserHandle.formatUid(pw, reg.uid); + pw.print(" "); pw.print(reg.pkg); + final IUidObserver observer = mUidObservers.getRegisteredCallbackItem(i); + pw.print(" "); pw.print(observer.getClass().getTypeName()); pw.print(":"); + if ((reg.which&ActivityManager.UID_OBSERVER_IDLE) != 0) { + pw.print(" IDLE"); + } + if ((reg.which&ActivityManager.UID_OBSERVER_ACTIVE) != 0) { + pw.print(" ACT" ); + } + if ((reg.which&ActivityManager.UID_OBSERVER_GONE) != 0) { + pw.print(" GONE"); + } + if ((reg.which&ActivityManager.UID_OBSERVER_PROCSTATE) != 0) { + pw.print(" STATE"); + pw.print(" (cut="); pw.print(reg.cutpoint); + pw.print(")"); + } + pw.println(); + if (reg.lastProcStates != null) { + final int NJ = reg.lastProcStates.size(); + for (int j=0; j<NJ; j++) { + pw.print(" Last "); + UserHandle.formatUid(pw, reg.lastProcStates.keyAt(j)); + pw.print(": "); pw.println(reg.lastProcStates.valueAt(j)); + } + } + } + } + + pw.println(); + pw.print(" mUidChangeDispatchCount="); + pw.print(mUidChangeDispatchCount); + pw.println(); + pw.println(" Slow UID dispatches:"); + final int N = mUidObservers.beginBroadcast(); + for (int i = 0; i < N; i++) { + UidObserverRegistration r = + (UidObserverRegistration) mUidObservers.getBroadcastCookie(i); + pw.print(" "); + pw.print(mUidObservers.getBroadcastItem(i).getClass().getTypeName()); + pw.print(": "); + pw.print(r.mSlowDispatchCount); + pw.print(" / Max "); + pw.print(r.mMaxDispatchTime); + pw.println("ms"); + } + mUidObservers.finishBroadcast(); + } + + @GuardedBy("mService") + void dumpDebug(ProtoOutputStream proto, String dumpPackage) { + final int NI = mUidObservers.getRegisteredCallbackCount(); + for (int i=0; i<NI; i++) { + final UidObserverRegistration reg = (UidObserverRegistration) + mUidObservers.getRegisteredCallbackCookie(i); + if (dumpPackage == null || dumpPackage.equals(reg.pkg)) { + reg.dumpDebug(proto, ActivityManagerServiceDumpProcessesProto.UID_OBSERVERS); + } + } + } + + static final class UidObserverRegistration { + final int uid; + final String pkg; + final int which; + final int cutpoint; + + /** + * Total # of callback calls that took more than {@link #SLOW_UID_OBSERVER_THRESHOLD_MS}. + * We show it in dumpsys. + */ + int mSlowDispatchCount; + + /** Max time it took for each dispatch. */ + int mMaxDispatchTime; + + final SparseIntArray lastProcStates; + + // Please keep the enum lists in sync + private static int[] ORIG_ENUMS = new int[]{ + ActivityManager.UID_OBSERVER_IDLE, + ActivityManager.UID_OBSERVER_ACTIVE, + ActivityManager.UID_OBSERVER_GONE, + ActivityManager.UID_OBSERVER_PROCSTATE, + }; + private static int[] PROTO_ENUMS = new int[]{ + ActivityManagerProto.UID_OBSERVER_FLAG_IDLE, + ActivityManagerProto.UID_OBSERVER_FLAG_ACTIVE, + ActivityManagerProto.UID_OBSERVER_FLAG_GONE, + ActivityManagerProto.UID_OBSERVER_FLAG_PROCSTATE, + }; + + UidObserverRegistration(int _uid, String _pkg, int _which, int _cutpoint) { + uid = _uid; + pkg = _pkg; + which = _which; + cutpoint = _cutpoint; + if (cutpoint >= ActivityManager.MIN_PROCESS_STATE) { + lastProcStates = new SparseIntArray(); + } else { + lastProcStates = null; + } + } + + void dumpDebug(ProtoOutputStream proto, long fieldId) { + final long token = proto.start(fieldId); + proto.write(UidObserverRegistrationProto.UID, uid); + proto.write(UidObserverRegistrationProto.PACKAGE, pkg); + ProtoUtils.writeBitWiseFlagsToProtoEnum(proto, UidObserverRegistrationProto.FLAGS, + which, ORIG_ENUMS, PROTO_ENUMS); + proto.write(UidObserverRegistrationProto.CUT_POINT, cutpoint); + if (lastProcStates != null) { + final int NI = lastProcStates.size(); + for (int i=0; i<NI; i++) { + final long pToken = proto.start(UidObserverRegistrationProto.LAST_PROC_STATES); + proto.write(UidObserverRegistrationProto.ProcState.UID, + lastProcStates.keyAt(i)); + proto.write(UidObserverRegistrationProto.ProcState.STATE, + lastProcStates.valueAt(i)); + proto.end(pToken); + } + } + proto.end(token); + } + } +} diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 7420e0a6e828..83bf28e2d3ba 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -988,6 +988,8 @@ class UserController implements Handler.Callback { final ArrayList<IStopUserCallback> stopCallbacks; final ArrayList<KeyEvictedCallback> keyEvictedCallbacks; int userIdToLock = userId; + // Must get a reference to UserInfo before it's removed + final UserInfo userInfo = getUserInfo(userId); synchronized (mLock) { stopCallbacks = new ArrayList<>(uss.mStopCallbacks); keyEvictedCallbacks = new ArrayList<>(uss.mKeyEvictedCallbacks); @@ -1030,8 +1032,8 @@ class UserController implements Handler.Callback { if (stopped) { mInjector.systemServiceManagerCleanupUser(userId); mInjector.stackSupervisorRemoveUser(userId); + // Remove the user if it is ephemeral. - UserInfo userInfo = getUserInfo(userId); if (userInfo.isEphemeral() && !userInfo.preCreated) { mInjector.getUserManager().removeUserEvenWhenDisallowed(userId); } diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index ee441bf06d04..dfe8af155a04 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -6222,7 +6222,9 @@ public class AppOpsService extends IAppOpsService.Stub { int[] users; if (userId == UserHandle.USER_ALL) { - List<UserInfo> liveUsers = UserManager.get(mContext).getUsers(false); + // TODO(b/157921703): this call is returning all users, not just live ones - we + // need to either fix the method called, or rename the variable + List<UserInfo> liveUsers = UserManager.get(mContext).getUsers(); users = new int[liveUsers.size()]; for (int i = 0; i < liveUsers.size(); i++) { diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 2bbbbf1664d1..06ef58f8cc61 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -28,7 +28,7 @@ import android.media.AudioDeviceAttributes; import android.media.AudioRoutesInfo; import android.media.AudioSystem; import android.media.IAudioRoutesObserver; -import android.media.IStrategyPreferredDeviceDispatcher; +import android.media.IStrategyPreferredDevicesDispatcher; import android.media.MediaMetrics; import android.os.Binder; import android.os.Handler; @@ -47,6 +47,7 @@ import com.android.internal.annotations.GuardedBy; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.NoSuchElementException; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; @@ -526,23 +527,23 @@ import java.util.concurrent.atomic.AtomicBoolean; } } - /*package*/ int setPreferredDeviceForStrategySync(int strategy, - @NonNull AudioDeviceAttributes device) { - return mDeviceInventory.setPreferredDeviceForStrategySync(strategy, device); + /*package*/ int setPreferredDevicesForStrategySync(int strategy, + @NonNull List<AudioDeviceAttributes> devices) { + return mDeviceInventory.setPreferredDevicesForStrategySync(strategy, devices); } - /*package*/ int removePreferredDeviceForStrategySync(int strategy) { - return mDeviceInventory.removePreferredDeviceForStrategySync(strategy); + /*package*/ int removePreferredDevicesForStrategySync(int strategy) { + return mDeviceInventory.removePreferredDevicesForStrategySync(strategy); } - /*package*/ void registerStrategyPreferredDeviceDispatcher( - @NonNull IStrategyPreferredDeviceDispatcher dispatcher) { - mDeviceInventory.registerStrategyPreferredDeviceDispatcher(dispatcher); + /*package*/ void registerStrategyPreferredDevicesDispatcher( + @NonNull IStrategyPreferredDevicesDispatcher dispatcher) { + mDeviceInventory.registerStrategyPreferredDevicesDispatcher(dispatcher); } - /*package*/ void unregisterStrategyPreferredDeviceDispatcher( - @NonNull IStrategyPreferredDeviceDispatcher dispatcher) { - mDeviceInventory.unregisterStrategyPreferredDeviceDispatcher(dispatcher); + /*package*/ void unregisterStrategyPreferredDevicesDispatcher( + @NonNull IStrategyPreferredDevicesDispatcher dispatcher) { + mDeviceInventory.unregisterStrategyPreferredDevicesDispatcher(dispatcher); } //--------------------------------------------------------------------- @@ -683,14 +684,14 @@ import java.util.concurrent.atomic.AtomicBoolean; sendLMsgNoDelay(MSG_L_SPEAKERPHONE_CLIENT_DIED, SENDMSG_QUEUE, obj); } - /*package*/ void postSaveSetPreferredDeviceForStrategy(int strategy, - AudioDeviceAttributes device) + /*package*/ void postSaveSetPreferredDevicesForStrategy(int strategy, + List<AudioDeviceAttributes> devices) { - sendILMsgNoDelay(MSG_IL_SAVE_PREF_DEVICE_FOR_STRATEGY, SENDMSG_QUEUE, strategy, device); + sendILMsgNoDelay(MSG_IL_SAVE_PREF_DEVICES_FOR_STRATEGY, SENDMSG_QUEUE, strategy, devices); } - /*package*/ void postSaveRemovePreferredDeviceForStrategy(int strategy) { - sendIMsgNoDelay(MSG_I_SAVE_REMOVE_PREF_DEVICE_FOR_STRATEGY, SENDMSG_QUEUE, strategy); + /*package*/ void postSaveRemovePreferredDevicesForStrategy(int strategy) { + sendIMsgNoDelay(MSG_I_SAVE_REMOVE_PREF_DEVICES_FOR_STRATEGY, SENDMSG_QUEUE, strategy); } //--------------------------------------------------------------------- @@ -1082,14 +1083,15 @@ import java.util.concurrent.atomic.AtomicBoolean; info.mDevice, info.mState, info.mSupprNoisy, info.mMusicDevice); } } break; - case MSG_IL_SAVE_PREF_DEVICE_FOR_STRATEGY: { + case MSG_IL_SAVE_PREF_DEVICES_FOR_STRATEGY: { final int strategy = msg.arg1; - final AudioDeviceAttributes device = (AudioDeviceAttributes) msg.obj; - mDeviceInventory.onSaveSetPreferredDevice(strategy, device); + final List<AudioDeviceAttributes> devices = + (List<AudioDeviceAttributes>) msg.obj; + mDeviceInventory.onSaveSetPreferredDevices(strategy, devices); } break; - case MSG_I_SAVE_REMOVE_PREF_DEVICE_FOR_STRATEGY: { + case MSG_I_SAVE_REMOVE_PREF_DEVICES_FOR_STRATEGY: { final int strategy = msg.arg1; - mDeviceInventory.onSaveRemovePreferredDevice(strategy); + mDeviceInventory.onSaveRemovePreferredDevices(strategy); } break; case MSG_CHECK_MUTE_MUSIC: checkMessagesMuteMusic(0); @@ -1163,8 +1165,8 @@ import java.util.concurrent.atomic.AtomicBoolean; // a ScoClient died in BtHelper private static final int MSG_L_SCOCLIENT_DIED = 32; - private static final int MSG_IL_SAVE_PREF_DEVICE_FOR_STRATEGY = 33; - private static final int MSG_I_SAVE_REMOVE_PREF_DEVICE_FOR_STRATEGY = 34; + private static final int MSG_IL_SAVE_PREF_DEVICES_FOR_STRATEGY = 33; + private static final int MSG_I_SAVE_REMOVE_PREF_DEVICES_FOR_STRATEGY = 34; private static final int MSG_L_SPEAKERPHONE_CLIENT_DIED = 35; private static final int MSG_CHECK_MUTE_MUSIC = 36; diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index 02a846e3dc82..fbf07cc591ff 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -16,7 +16,6 @@ package com.android.server.audio; import android.annotation.NonNull; -import android.annotation.Nullable; import android.app.ActivityManager; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothAdapter; @@ -32,7 +31,7 @@ import android.media.AudioPort; import android.media.AudioRoutesInfo; import android.media.AudioSystem; import android.media.IAudioRoutesObserver; -import android.media.IStrategyPreferredDeviceDispatcher; +import android.media.IStrategyPreferredDevicesDispatcher; import android.media.MediaMetrics; import android.os.Binder; import android.os.RemoteCallbackList; @@ -51,6 +50,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedHashMap; +import java.util.List; import java.util.Set; /** @@ -137,7 +137,8 @@ public class AudioDeviceInventory { private final ArrayMap<Integer, String> mApmConnectedDevices = new ArrayMap<>(); // List of preferred devices for strategies - private final ArrayMap<Integer, AudioDeviceAttributes> mPreferredDevices = new ArrayMap<>(); + private final ArrayMap<Integer, List<AudioDeviceAttributes>> mPreferredDevices = + new ArrayMap<>(); // the wrapper for AudioSystem static methods, allows us to spy AudioSystem private final @NonNull AudioSystemAdapter mAudioSystem; @@ -150,8 +151,8 @@ public class AudioDeviceInventory { new RemoteCallbackList<IAudioRoutesObserver>(); // Monitoring of strategy-preferred device - final RemoteCallbackList<IStrategyPreferredDeviceDispatcher> mPrefDevDispatchers = - new RemoteCallbackList<IStrategyPreferredDeviceDispatcher>(); + final RemoteCallbackList<IStrategyPreferredDevicesDispatcher> mPrefDevDispatchers = + new RemoteCallbackList<IStrategyPreferredDevicesDispatcher>(); /*package*/ AudioDeviceInventory(@NonNull AudioDeviceBroker broker) { mDeviceBroker = broker; @@ -265,8 +266,9 @@ public class AudioDeviceInventory { } } synchronized (mPreferredDevices) { - mPreferredDevices.forEach((strategy, device) -> { - mAudioSystem.setPreferredDeviceForStrategy(strategy, device); }); + mPreferredDevices.forEach((strategy, devices) -> { + mAudioSystem.setDevicesRoleForStrategy( + strategy, AudioSystem.DEVICE_ROLE_PREFERRED, devices); }); } } @@ -600,49 +602,52 @@ public class AudioDeviceInventory { mmi.record(); } - /*package*/ void onSaveSetPreferredDevice(int strategy, @NonNull AudioDeviceAttributes device) { - mPreferredDevices.put(strategy, device); - dispatchPreferredDevice(strategy, device); + /*package*/ void onSaveSetPreferredDevices(int strategy, + @NonNull List<AudioDeviceAttributes> devices) { + mPreferredDevices.put(strategy, devices); + dispatchPreferredDevice(strategy, devices); } - /*package*/ void onSaveRemovePreferredDevice(int strategy) { + /*package*/ void onSaveRemovePreferredDevices(int strategy) { mPreferredDevices.remove(strategy); - dispatchPreferredDevice(strategy, null); + dispatchPreferredDevice(strategy, new ArrayList<AudioDeviceAttributes>()); } //------------------------------------------------------------ // - /*package*/ int setPreferredDeviceForStrategySync(int strategy, - @NonNull AudioDeviceAttributes device) { + /*package*/ int setPreferredDevicesForStrategySync(int strategy, + @NonNull List<AudioDeviceAttributes> devices) { final long identity = Binder.clearCallingIdentity(); - final int status = mAudioSystem.setPreferredDeviceForStrategy(strategy, device); + final int status = mAudioSystem.setDevicesRoleForStrategy( + strategy, AudioSystem.DEVICE_ROLE_PREFERRED, devices); Binder.restoreCallingIdentity(identity); if (status == AudioSystem.SUCCESS) { - mDeviceBroker.postSaveSetPreferredDeviceForStrategy(strategy, device); + mDeviceBroker.postSaveSetPreferredDevicesForStrategy(strategy, devices); } return status; } - /*package*/ int removePreferredDeviceForStrategySync(int strategy) { + /*package*/ int removePreferredDevicesForStrategySync(int strategy) { final long identity = Binder.clearCallingIdentity(); - final int status = mAudioSystem.removePreferredDeviceForStrategy(strategy); + final int status = mAudioSystem.removeDevicesRoleForStrategy( + strategy, AudioSystem.DEVICE_ROLE_PREFERRED); Binder.restoreCallingIdentity(identity); if (status == AudioSystem.SUCCESS) { - mDeviceBroker.postSaveRemovePreferredDeviceForStrategy(strategy); + mDeviceBroker.postSaveRemovePreferredDevicesForStrategy(strategy); } return status; } - /*package*/ void registerStrategyPreferredDeviceDispatcher( - @NonNull IStrategyPreferredDeviceDispatcher dispatcher) { + /*package*/ void registerStrategyPreferredDevicesDispatcher( + @NonNull IStrategyPreferredDevicesDispatcher dispatcher) { mPrefDevDispatchers.register(dispatcher); } - /*package*/ void unregisterStrategyPreferredDeviceDispatcher( - @NonNull IStrategyPreferredDeviceDispatcher dispatcher) { + /*package*/ void unregisterStrategyPreferredDevicesDispatcher( + @NonNull IStrategyPreferredDevicesDispatcher dispatcher) { mPrefDevDispatchers.unregister(dispatcher); } @@ -1288,11 +1293,13 @@ public class AudioDeviceInventory { } } - private void dispatchPreferredDevice(int strategy, @Nullable AudioDeviceAttributes device) { + private void dispatchPreferredDevice(int strategy, + @NonNull List<AudioDeviceAttributes> devices) { final int nbDispatchers = mPrefDevDispatchers.beginBroadcast(); for (int i = 0; i < nbDispatchers; i++) { try { - mPrefDevDispatchers.getBroadcastItem(i).dispatchPrefDeviceChanged(strategy, device); + mPrefDevDispatchers.getBroadcastItem(i).dispatchPrefDevicesChanged( + strategy, devices); } catch (RemoteException e) { } } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 23b09294260c..bf7c68a845c5 100755 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -83,7 +83,7 @@ import android.media.IAudioService; import android.media.IPlaybackConfigDispatcher; import android.media.IRecordingConfigDispatcher; import android.media.IRingtonePlayer; -import android.media.IStrategyPreferredDeviceDispatcher; +import android.media.IStrategyPreferredDevicesDispatcher; import android.media.IVolumeController; import android.media.MediaExtractor; import android.media.MediaFormat; @@ -167,6 +167,7 @@ import java.util.Objects; import java.util.Set; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; /** * The implementation of the audio service for volume, audio focus, device management... @@ -1282,7 +1283,6 @@ public class AudioService extends IAudioService.Stub } if (isPlatformTelevision()) { - checkAddAllFixedVolumeDevices(AudioSystem.DEVICE_OUT_HDMI, caller); synchronized (mHdmiClientLock) { if (mHdmiManager != null && mHdmiPlaybackClient != null) { updateHdmiCecSinkLocked(mHdmiCecSink | false); @@ -1302,22 +1302,54 @@ public class AudioService extends IAudioService.Stub } } - private void checkAddAllFixedVolumeDevices(int device, String caller) { + /** + * Update volume states for the given device. + * + * This will initialize the volume index if no volume index is available. + * If the device is the currently routed device, fixed/full volume policies will be applied. + * + * @param device a single audio device, ensure that this is not a devices bitmask + * @param caller caller of this method + */ + private void updateVolumeStatesForAudioDevice(int device, String caller) { final int numStreamTypes = AudioSystem.getNumStreamTypes(); for (int streamType = 0; streamType < numStreamTypes; streamType++) { - if (!mStreamStates[streamType].hasIndexForDevice(device)) { - // set the default value, if device is affected by a full/fix/abs volume rule, it - // will taken into account in checkFixedVolumeDevices() - mStreamStates[streamType].setIndex( - mStreamStates[mStreamVolumeAlias[streamType]] - .getIndex(AudioSystem.DEVICE_OUT_DEFAULT), - device, caller, true /*hasModifyAudioSettings*/); - } - mStreamStates[streamType].checkFixedVolumeDevices(); + updateVolumeStates(device, streamType, caller); + } + } - // Unmute streams if device is full volume - if (mFullVolumeDevices.contains(device)) { - mStreamStates[streamType].mute(false); + /** + * Update volume states for the given device and given stream. + * + * This will initialize the volume index if no volume index is available. + * If the device is the currently routed device, fixed/full volume policies will be applied. + * + * @param device a single audio device, ensure that this is not a devices bitmask + * @param streamType streamType to be updated + * @param caller caller of this method + */ + private void updateVolumeStates(int device, int streamType, String caller) { + if (!mStreamStates[streamType].hasIndexForDevice(device)) { + // set the default value, if device is affected by a full/fix/abs volume rule, it + // will taken into account in checkFixedVolumeDevices() + mStreamStates[streamType].setIndex( + mStreamStates[mStreamVolumeAlias[streamType]] + .getIndex(AudioSystem.DEVICE_OUT_DEFAULT), + device, caller, true /*hasModifyAudioSettings*/); + } + + // Check if device to be updated is routed for the given audio stream + List<AudioDeviceAttributes> devicesForAttributes = getDevicesForAttributesInt( + new AudioAttributes.Builder().setInternalLegacyStreamType(streamType).build()); + for (AudioDeviceAttributes deviceAttributes : devicesForAttributes) { + if (deviceAttributes.getType() == AudioDeviceInfo.convertInternalDeviceToDeviceType( + device)) { + mStreamStates[streamType].checkFixedVolumeDevices(); + + // Unmute streams if required if device is full volume + if (isStreamMute(streamType) && mFullVolumeDevices.contains(device)) { + mStreamStates[streamType].mute(false); + } } } } @@ -1777,22 +1809,28 @@ public class AudioService extends IAudioService.Stub /////////////////////////////////////////////////////////////////////////// // IPC methods /////////////////////////////////////////////////////////////////////////// - /** @see AudioManager#setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceInfo) */ - public int setPreferredDeviceForStrategy(int strategy, AudioDeviceAttributes device) { - if (device == null) { + /** + * @see AudioManager#setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes) + * @see AudioManager#setPreferredDevicesForStrategy(AudioProductStrategy, + * List<AudioDeviceAttributes>) + */ + public int setPreferredDevicesForStrategy(int strategy, List<AudioDeviceAttributes> devices) { + if (devices == null) { return AudioSystem.ERROR; } enforceModifyAudioRoutingPermission(); final String logString = String.format( "setPreferredDeviceForStrategy u/pid:%d/%d strat:%d dev:%s", - Binder.getCallingUid(), Binder.getCallingPid(), strategy, device.toString()); + Binder.getCallingUid(), Binder.getCallingPid(), strategy, + devices.stream().map(e -> e.toString()).collect(Collectors.joining(","))); sDeviceLogger.log(new AudioEventLogger.StringEvent(logString).printLog(TAG)); - if (device.getRole() == AudioDeviceAttributes.ROLE_INPUT) { + if (devices.stream().anyMatch(device -> + device.getRole() == AudioDeviceAttributes.ROLE_INPUT)) { Log.e(TAG, "Unsupported input routing in " + logString); return AudioSystem.ERROR; } - final int status = mDeviceBroker.setPreferredDeviceForStrategySync(strategy, device); + final int status = mDeviceBroker.setPreferredDevicesForStrategySync(strategy, devices); if (status != AudioSystem.SUCCESS) { Log.e(TAG, String.format("Error %d in %s)", status, logString)); } @@ -1801,60 +1839,73 @@ public class AudioService extends IAudioService.Stub } /** @see AudioManager#removePreferredDeviceForStrategy(AudioProductStrategy) */ - public int removePreferredDeviceForStrategy(int strategy) { + public int removePreferredDevicesForStrategy(int strategy) { enforceModifyAudioRoutingPermission(); final String logString = String.format("removePreferredDeviceForStrategy strat:%d", strategy); sDeviceLogger.log(new AudioEventLogger.StringEvent(logString).printLog(TAG)); - final int status = mDeviceBroker.removePreferredDeviceForStrategySync(strategy); + final int status = mDeviceBroker.removePreferredDevicesForStrategySync(strategy); if (status != AudioSystem.SUCCESS) { Log.e(TAG, String.format("Error %d in %s)", status, logString)); } return status; } - /** @see AudioManager#getPreferredDeviceForStrategy(AudioProductStrategy) */ - public AudioDeviceAttributes getPreferredDeviceForStrategy(int strategy) { + /** + * @see AudioManager#getPreferredDeviceForStrategy(AudioProductStrategy) + * @see AudioManager#getPreferredDevicesForStrategy(AudioProductStrategy) + */ + public List<AudioDeviceAttributes> getPreferredDevicesForStrategy(int strategy) { enforceModifyAudioRoutingPermission(); - AudioDeviceAttributes[] devices = new AudioDeviceAttributes[1]; + List<AudioDeviceAttributes> devices = new ArrayList<>(); final long identity = Binder.clearCallingIdentity(); - final int status = AudioSystem.getPreferredDeviceForStrategy(strategy, devices); + final int status = AudioSystem.getDevicesForRoleAndStrategy( + strategy, AudioSystem.DEVICE_ROLE_PREFERRED, devices); Binder.restoreCallingIdentity(identity); if (status != AudioSystem.SUCCESS) { Log.e(TAG, String.format("Error %d in getPreferredDeviceForStrategy(%d)", status, strategy)); - return null; + return new ArrayList<AudioDeviceAttributes>(); } else { - return devices[0]; + return devices; } } - /** @see AudioManager#addOnPreferredDeviceForStrategyChangedListener(Executor, AudioManager.OnPreferredDeviceForStrategyChangedListener) */ - public void registerStrategyPreferredDeviceDispatcher( - @Nullable IStrategyPreferredDeviceDispatcher dispatcher) { + /** @see AudioManager#addOnPreferredDevicesForStrategyChangedListener( + * Executor, AudioManager.OnPreferredDevicesForStrategyChangedListener) + */ + public void registerStrategyPreferredDevicesDispatcher( + @Nullable IStrategyPreferredDevicesDispatcher dispatcher) { if (dispatcher == null) { return; } enforceModifyAudioRoutingPermission(); - mDeviceBroker.registerStrategyPreferredDeviceDispatcher(dispatcher); + mDeviceBroker.registerStrategyPreferredDevicesDispatcher(dispatcher); } - /** @see AudioManager#removeOnPreferredDeviceForStrategyChangedListener(AudioManager.OnPreferredDeviceForStrategyChangedListener) */ - public void unregisterStrategyPreferredDeviceDispatcher( - @Nullable IStrategyPreferredDeviceDispatcher dispatcher) { + /** @see AudioManager#removeOnPreferredDevicesForStrategyChangedListener( + * AudioManager.OnPreferredDevicesForStrategyChangedListener) + */ + public void unregisterStrategyPreferredDevicesDispatcher( + @Nullable IStrategyPreferredDevicesDispatcher dispatcher) { if (dispatcher == null) { return; } enforceModifyAudioRoutingPermission(); - mDeviceBroker.unregisterStrategyPreferredDeviceDispatcher(dispatcher); + mDeviceBroker.unregisterStrategyPreferredDevicesDispatcher(dispatcher); } /** @see AudioManager#getDevicesForAttributes(AudioAttributes) */ public @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributes( @NonNull AudioAttributes attributes) { - Objects.requireNonNull(attributes); enforceModifyAudioRoutingPermission(); + return getDevicesForAttributesInt(attributes); + } + + protected @NonNull ArrayList<AudioDeviceAttributes> getDevicesForAttributesInt( + @NonNull AudioAttributes attributes) { + Objects.requireNonNull(attributes); return AudioSystem.getDevicesForAttributes(attributes); } @@ -4901,7 +4952,15 @@ public class AudioService extends IAudioService.Stub synchronized (VolumeStreamState.class) { for (int stream = 0; stream < mStreamStates.length; stream++) { if (stream != skipStream) { - mStreamStates[stream].observeDevicesForStream_syncVSS(false /*checkOthers*/); + int devices = mStreamStates[stream].observeDevicesForStream_syncVSS( + false /*checkOthers*/); + + Set<Integer> devicesSet = AudioSystem.generateAudioDeviceTypesSet(devices); + for (Integer device : devicesSet) { + // Update volume states for devices routed for the stream + updateVolumeStates(device, stream, + "AudioService#observeDevicesForStreams"); + } } } } @@ -4970,7 +5029,7 @@ public class AudioService extends IAudioService.Stub + Integer.toHexString(audioSystemDeviceOut) + " from:" + caller)); // make sure we have a volume entry for this device, and that volume is updated according // to volume behavior - checkAddAllFixedVolumeDevices(audioSystemDeviceOut, "setDeviceVolumeBehavior:" + caller); + updateVolumeStatesForAudioDevice(audioSystemDeviceOut, "setDeviceVolumeBehavior:" + caller); } /** @@ -7192,10 +7251,9 @@ public class AudioService extends IAudioService.Stub // HDMI output removeAudioSystemDeviceOutFromFullVolumeDevices(AudioSystem.DEVICE_OUT_HDMI); } + updateVolumeStatesForAudioDevice(AudioSystem.DEVICE_OUT_HDMI, + "HdmiPlaybackClient.DisplayStatusCallback"); } - - checkAddAllFixedVolumeDevices(AudioSystem.DEVICE_OUT_HDMI, - "HdmiPlaybackClient.DisplayStatusCallback"); } private class MyHdmiControlStatusChangeListenerCallback diff --git a/services/core/java/com/android/server/audio/AudioSystemAdapter.java b/services/core/java/com/android/server/audio/AudioSystemAdapter.java index e60243fc481c..a0e1ca78a5e7 100644 --- a/services/core/java/com/android/server/audio/AudioSystemAdapter.java +++ b/services/core/java/com/android/server/audio/AudioSystemAdapter.java @@ -20,6 +20,8 @@ import android.annotation.NonNull; import android.media.AudioDeviceAttributes; import android.media.AudioSystem; +import java.util.List; + /** * Provides an adapter to access functionality of the android.media.AudioSystem class for device * related functionality. @@ -77,22 +79,25 @@ public class AudioSystemAdapter { } /** - * Same as {@link AudioSystem#setPreferredDeviceForStrategy(int, AudioDeviceAttributes)} + * Same as {@link AudioSystem#setDevicesRoleForStrategy(int, int, List)} * @param strategy - * @param device + * @param role + * @param devices * @return */ - public int setPreferredDeviceForStrategy(int strategy, @NonNull AudioDeviceAttributes device) { - return AudioSystem.setPreferredDeviceForStrategy(strategy, device); + public int setDevicesRoleForStrategy(int strategy, int role, + @NonNull List<AudioDeviceAttributes> devices) { + return AudioSystem.setDevicesRoleForStrategy(strategy, role, devices); } /** - * Same as {@link AudioSystem#removePreferredDeviceForStrategy(int)} + * Same as {@link AudioSystem#removeDevicesRoleForStrategy(int, int)} * @param strategy + * @param role * @return */ - public int removePreferredDeviceForStrategy(int strategy) { - return AudioSystem.removePreferredDeviceForStrategy(strategy); + public int removeDevicesRoleForStrategy(int strategy, int role) { + return AudioSystem.removeDevicesRoleForStrategy(strategy, role); } /** diff --git a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java index ab48fdb0fd6e..e87c8fe092fe 100644 --- a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java @@ -98,7 +98,7 @@ public abstract class AcquisitionClient<T> extends ClientMonitor<T> implements I } if (finish) { - mFinishCallback.onClientFinished(this, false /* success */); + mCallback.onClientFinished(this, false /* success */); } } @@ -114,7 +114,7 @@ public abstract class AcquisitionClient<T> extends ClientMonitor<T> implements I } @Override - public void cancelWithoutStarting(@NonNull FinishCallback finishCallback) { + public void cancelWithoutStarting(@NonNull Callback callback) { final int errorCode = BiometricConstants.BIOMETRIC_ERROR_CANCELED; try { if (getListener() != null) { @@ -123,7 +123,7 @@ public abstract class AcquisitionClient<T> extends ClientMonitor<T> implements I } catch (RemoteException e) { Slog.w(TAG, "Failed to invoke sendError", e); } - finishCallback.onClientFinished(this, true /* success */); + callback.onClientFinished(this, true /* success */); } /** @@ -155,7 +155,7 @@ public abstract class AcquisitionClient<T> extends ClientMonitor<T> implements I } } catch (RemoteException e) { Slog.w(TAG, "Failed to invoke sendAcquired", e); - mFinishCallback.onClientFinished(this, false /* success */); + mCallback.onClientFinished(this, false /* success */); } } diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java index cb2321f524f6..47c839cb329a 100644 --- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java @@ -191,7 +191,7 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T> } } catch (RemoteException e) { Slog.e(TAG, "Unable to notify listener, finishing", e); - mFinishCallback.onClientFinished(this, false /* success */); + mCallback.onClientFinished(this, false /* success */); } } @@ -211,8 +211,8 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T> * Start authentication */ @Override - public void start(@NonNull FinishCallback finishCallback) { - super.start(finishCallback); + public void start(@NonNull Callback callback) { + super.start(callback); final @LockoutTracker.LockoutMode int lockoutMode = mLockoutTracker.getLockoutModeForUser(getTargetUserId()); diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java index 4f37dccea42e..fffc07320f84 100644 --- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java +++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java @@ -85,7 +85,7 @@ public class BiometricScheduler { static final int STATE_WAITING_FOR_COOKIE = 4; /** - * The {@link ClientMonitor.FinishCallback} has been invoked and the client is finished. + * The {@link ClientMonitor.Callback} has been invoked and the client is finished. */ static final int STATE_FINISHED = 5; @@ -99,13 +99,13 @@ public class BiometricScheduler { @interface OperationState {} @NonNull final ClientMonitor<?> clientMonitor; - @Nullable final ClientMonitor.FinishCallback clientFinishCallback; + @Nullable final ClientMonitor.Callback mClientCallback; @OperationState int state; Operation(@NonNull ClientMonitor<?> clientMonitor, - @Nullable ClientMonitor.FinishCallback finishCallback) { + @Nullable ClientMonitor.Callback callback) { this.clientMonitor = clientMonitor; - this.clientFinishCallback = finishCallback; + this.mClientCallback = callback; state = STATE_WAITING_IN_QUEUE; } @@ -133,7 +133,7 @@ public class BiometricScheduler { public void run() { if (operation.state != Operation.STATE_FINISHED) { Slog.e(tag, "[Watchdog Triggered]: " + operation); - operation.clientMonitor.mFinishCallback + operation.clientMonitor.mCallback .onClientFinished(operation.clientMonitor, false /* success */); } } @@ -175,15 +175,15 @@ public class BiometricScheduler { @Nullable private final GestureAvailabilityDispatcher mGestureAvailabilityDispatcher; @NonNull private final IBiometricService mBiometricService; @NonNull private final Handler mHandler = new Handler(Looper.getMainLooper()); - @NonNull private final InternalFinishCallback mInternalFinishCallback; + @NonNull protected final InternalCallback mInternalCallback; @NonNull private final Queue<Operation> mPendingOperations; @Nullable private Operation mCurrentOperation; @NonNull private final ArrayDeque<CrashState> mCrashStates; - // Internal finish callback, notified when an operation is complete. Notifies the requester + // Internal callback, notified when an operation is complete. Notifies the requester // that the operation is complete, before performing internal scheduler work (such as // starting the next client). - private class InternalFinishCallback implements ClientMonitor.FinishCallback { + public class InternalCallback implements ClientMonitor.Callback { @Override public void onClientFinished(ClientMonitor<?> clientMonitor, boolean success) { mHandler.post(() -> { @@ -203,8 +203,8 @@ public class BiometricScheduler { Slog.d(getTag(), "[Finishing] " + clientMonitor + ", success: " + success); mCurrentOperation.state = Operation.STATE_FINISHED; - if (mCurrentOperation.clientFinishCallback != null) { - mCurrentOperation.clientFinishCallback.onClientFinished(clientMonitor, success); + if (mCurrentOperation.mClientCallback != null) { + mCurrentOperation.mClientCallback.onClientFinished(clientMonitor, success); } if (mGestureAvailabilityDispatcher != null) { @@ -227,7 +227,7 @@ public class BiometricScheduler { public BiometricScheduler(@NonNull String tag, @Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher) { mBiometricTag = tag; - mInternalFinishCallback = new InternalFinishCallback(); + mInternalCallback = new InternalCallback(); mGestureAvailabilityDispatcher = gestureAvailabilityDispatcher; mPendingOperations = new ArrayDeque<>(); mBiometricService = IBiometricService.Stub.asInterface( @@ -262,7 +262,7 @@ public class BiometricScheduler { } final Interruptable interruptable = (Interruptable) currentClient; - interruptable.cancelWithoutStarting(mInternalFinishCallback); + interruptable.cancelWithoutStarting(mInternalCallback); // Now we wait for the client to send its FinishCallback, which kicks off the next // operation. return; @@ -280,7 +280,10 @@ public class BiometricScheduler { final boolean shouldStartNow = currentClient.getCookie() == 0; if (shouldStartNow) { Slog.d(getTag(), "[Starting] " + mCurrentOperation); - currentClient.start(mInternalFinishCallback); + if (mCurrentOperation.mClientCallback != null) { + mCurrentOperation.mClientCallback.onClientStarted(currentClient); + } + currentClient.start(mInternalCallback); mCurrentOperation.state = Operation.STATE_STARTED; } else { try { @@ -323,8 +326,11 @@ public class BiometricScheduler { } Slog.d(getTag(), "[Starting] Prepared client: " + mCurrentOperation); + if (mCurrentOperation.mClientCallback != null) { + mCurrentOperation.mClientCallback.onClientStarted(mCurrentOperation.clientMonitor); + } mCurrentOperation.state = Operation.STATE_STARTED; - mCurrentOperation.clientMonitor.start(mInternalFinishCallback); + mCurrentOperation.clientMonitor.start(mInternalCallback); } /** @@ -340,11 +346,11 @@ public class BiometricScheduler { * Adds a {@link ClientMonitor} to the pending queue * * @param clientMonitor operation to be scheduled - * @param clientFinishCallback optional callback, invoked when the client is finished, but + * @param clientCallback optional callback, invoked when the client is finished, but * before it has been removed from the queue. */ public void scheduleClientMonitor(@NonNull ClientMonitor<?> clientMonitor, - @Nullable ClientMonitor.FinishCallback clientFinishCallback) { + @Nullable ClientMonitor.Callback clientCallback) { // Mark any interruptable pending clients as canceling. Once they reach the head of the // queue, the scheduler will send ERROR_CANCELED and skip the operation. for (Operation operation : mPendingOperations) { @@ -356,7 +362,7 @@ public class BiometricScheduler { } } - mPendingOperations.add(new Operation(clientMonitor, clientFinishCallback)); + mPendingOperations.add(new Operation(clientMonitor, clientCallback)); Slog.d(getTag(), "[Added] " + clientMonitor + ", new queue size: " + mPendingOperations.size()); diff --git a/services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java index 8b27781940ac..81867b02aed9 100644 --- a/services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java +++ b/services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java @@ -42,7 +42,15 @@ public abstract class ClientMonitor<T> extends LoggableMonitor implements IBinde /** * Interface that ClientMonitor holders should use to receive callbacks. */ - public interface FinishCallback { + public interface Callback { + /** + * Invoked when the ClientMonitor operation has been started (e.g. reached the head of + * the queue and becomes the current operation). + * + * @param clientMonitor Reference of the ClientMonitor that is starting. + */ + default void onClientStarted(@NonNull ClientMonitor<?> clientMonitor) {} + /** * Invoked when the ClientMonitor operation is complete. This abstracts away asynchronous * (i.e. Authenticate, Enroll, Enumerate, Remove) and synchronous (i.e. generateChallenge, @@ -52,7 +60,7 @@ public abstract class ClientMonitor<T> extends LoggableMonitor implements IBinde * @param clientMonitor Reference of the ClientMonitor that finished. * @param success True if the operation completed successfully. */ - void onClientFinished(ClientMonitor<?> clientMonitor, boolean success); + default void onClientFinished(@NonNull ClientMonitor<?> clientMonitor, boolean success) {} } /** @@ -79,7 +87,7 @@ public abstract class ClientMonitor<T> extends LoggableMonitor implements IBinde private final int mCookie; boolean mAlreadyDone; - @NonNull protected FinishCallback mFinishCallback; + @NonNull protected Callback mCallback; /** * @param context system_server context @@ -125,17 +133,17 @@ public abstract class ClientMonitor<T> extends LoggableMonitor implements IBinde /** * Invoked if the scheduler is unable to start the ClientMonitor (for example the HAL is null). * If such a problem is detected, the scheduler will not invoke - * {@link #start(FinishCallback)}. + * {@link #start(Callback)}. */ public abstract void unableToStart(); /** * Starts the ClientMonitor's lifecycle. Invokes {@link #startHalOperation()} when internal book * keeping is complete. - * @param finishCallback invoked when the operation is complete (succeeds, fails, etc) + * @param callback invoked when the operation is complete (succeeds, fails, etc) */ - public void start(@NonNull FinishCallback finishCallback) { - mFinishCallback = finishCallback; + public void start(@NonNull Callback callback) { + mCallback = callback; } /** diff --git a/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java index 3cef6667b644..2c60d096bd13 100644 --- a/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java +++ b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java @@ -142,10 +142,21 @@ public final class ClientMonitorCallbackConverter { } } - public void onFeatureGet(boolean success, int feature, boolean value) - throws RemoteException { + public void onFeatureGet(boolean success, int feature, boolean value) throws RemoteException { if (mFaceServiceReceiver != null) { mFaceServiceReceiver.onFeatureGet(success, feature, value); } } + + public void onChallengeInterrupted(int sensorId) throws RemoteException { + if (mFaceServiceReceiver != null) { + mFaceServiceReceiver.onChallengeInterrupted(sensorId); + } + } + + public void onChallengeInterruptFinished(int sensorId) throws RemoteException { + if (mFaceServiceReceiver != null) { + mFaceServiceReceiver.onChallengeInterruptFinished(sensorId); + } + } } diff --git a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java index add5829c1342..8bf9680d60cd 100644 --- a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java @@ -77,18 +77,18 @@ public abstract class EnrollClient<T> extends AcquisitionClient<T> { mBiometricUtils.addBiometricForUser(getContext(), getTargetUserId(), identifier); logOnEnrolled(getTargetUserId(), System.currentTimeMillis() - mEnrollmentStartTimeMs, true /* enrollSuccessful */); - mFinishCallback.onClientFinished(this, true /* success */); + mCallback.onClientFinished(this, true /* success */); } notifyUserActivity(); } @Override - public void start(@NonNull FinishCallback finishCallback) { - super.start(finishCallback); + public void start(@NonNull Callback callback) { + super.start(callback); if (hasReachedEnrollmentLimit()) { Slog.e(TAG, "Reached enrollment limit"); - finishCallback.onClientFinished(this, false /* success */); + callback.onClientFinished(this, false /* success */); return; } diff --git a/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java index dad5cad1ed8d..2c5b8027f309 100644 --- a/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java @@ -47,16 +47,16 @@ public abstract class GenerateChallengeClient<T> extends ClientMonitor<T> { } @Override - public void start(@NonNull FinishCallback finishCallback) { - super.start(finishCallback); + public void start(@NonNull Callback callback) { + super.start(callback); startHalOperation(); try { getListener().onChallengeGenerated(mChallenge); - mFinishCallback.onClientFinished(this, true /* success */); + mCallback.onClientFinished(this, true /* success */); } catch (RemoteException e) { Slog.e(TAG, "Remote exception", e); - mFinishCallback.onClientFinished(this, false /* success */); + mCallback.onClientFinished(this, false /* success */); } } } diff --git a/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java b/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java index 6d7b0fd3d5f1..5c08bce9b44f 100644 --- a/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java @@ -62,29 +62,35 @@ public abstract class InternalCleanupClient<S extends BiometricAuthenticator.Ide private final List<S> mEnrolledList; private ClientMonitor<T> mCurrentTask; - private final FinishCallback mEnumerateFinishCallback = (clientMonitor, success) -> { - final List<BiometricAuthenticator.Identifier> unknownHALTemplates = - ((InternalEnumerateClient<T>) mCurrentTask).getUnknownHALTemplates(); - - if (!unknownHALTemplates.isEmpty()) { - Slog.w(TAG, "Adding " + unknownHALTemplates.size() + " templates for deletion"); - } - for (BiometricAuthenticator.Identifier unknownHALTemplate : unknownHALTemplates) { - mUnknownHALTemplates.add(new UserTemplate(unknownHALTemplate, - mCurrentTask.getTargetUserId())); - } - - if (mUnknownHALTemplates.isEmpty()) { - // No unknown HAL templates. Unknown framework templates are already cleaned up in - // InternalEnumerateClient. Finish this client. - mFinishCallback.onClientFinished(this, success); - } else { - startCleanupUnknownHalTemplates(); + private final Callback mEnumerateCallback = new Callback() { + @Override + public void onClientFinished(@NonNull ClientMonitor<?> clientMonitor, boolean success) { + final List<BiometricAuthenticator.Identifier> unknownHALTemplates = + ((InternalEnumerateClient<T>) mCurrentTask).getUnknownHALTemplates(); + + if (!unknownHALTemplates.isEmpty()) { + Slog.w(TAG, "Adding " + unknownHALTemplates.size() + " templates for deletion"); + } + for (BiometricAuthenticator.Identifier unknownHALTemplate : unknownHALTemplates) { + mUnknownHALTemplates.add(new UserTemplate(unknownHALTemplate, + mCurrentTask.getTargetUserId())); + } + + if (mUnknownHALTemplates.isEmpty()) { + // No unknown HAL templates. Unknown framework templates are already cleaned up in + // InternalEnumerateClient. Finish this client. + mCallback.onClientFinished(InternalCleanupClient.this, success); + } else { + startCleanupUnknownHalTemplates(); + } } }; - private final FinishCallback mRemoveFinishCallback = (clientMonitor, success) -> { - mFinishCallback.onClientFinished(this, success); + private final Callback mRemoveCallback = new Callback() { + @Override + public void onClientFinished(@NonNull ClientMonitor<?> clientMonitor, boolean success) { + mCallback.onClientFinished(InternalCleanupClient.this, success); + } }; protected abstract InternalEnumerateClient<T> getEnumerateClient(Context context, @@ -116,7 +122,7 @@ public abstract class InternalCleanupClient<S extends BiometricAuthenticator.Ide FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED, mStatsModality, BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_HAL); - mCurrentTask.start(mRemoveFinishCallback); + mCurrentTask.start(mRemoveCallback); } @Override @@ -125,13 +131,13 @@ public abstract class InternalCleanupClient<S extends BiometricAuthenticator.Ide } @Override - public void start(@NonNull FinishCallback finishCallback) { - super.start(finishCallback); + public void start(@NonNull Callback callback) { + super.start(callback); // Start enumeration. Removal will start if necessary, when enumeration is completed. mCurrentTask = getEnumerateClient(getContext(), mLazyDaemon, getToken(), getTargetUserId(), getOwnerString(), mEnrolledList, mBiometricUtils, getSensorId()); - mCurrentTask.start(mEnumerateFinishCallback); + mCurrentTask.start(mEnumerateCallback); } @Override @@ -147,7 +153,7 @@ public abstract class InternalCleanupClient<S extends BiometricAuthenticator.Ide + mCurrentTask.getClass().getSimpleName()); return; } - ((RemovalClient) mCurrentTask).onRemoved(identifier, remaining); + ((RemovalClient<T>) mCurrentTask).onRemoved(identifier, remaining); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java b/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java index 3f73cd56e6c3..e07f71298d13 100644 --- a/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java @@ -62,7 +62,7 @@ public abstract class InternalEnumerateClient<T> extends ClientMonitor<T> handleEnumeratedTemplate(identifier); if (remaining == 0) { doTemplateCleanup(); - mFinishCallback.onClientFinished(this, true /* success */); + mCallback.onClientFinished(this, true /* success */); } } @@ -72,8 +72,8 @@ public abstract class InternalEnumerateClient<T> extends ClientMonitor<T> } @Override - public void start(@NonNull FinishCallback finishCallback) { - super.start(finishCallback); + public void start(@NonNull Callback callback) { + super.start(callback); // The biometric template ids will be removed when we get confirmation from the HAL startHalOperation(); diff --git a/services/core/java/com/android/server/biometrics/sensors/Interruptable.java b/services/core/java/com/android/server/biometrics/sensors/Interruptable.java index 35d917747574..28e0117afd36 100644 --- a/services/core/java/com/android/server/biometrics/sensors/Interruptable.java +++ b/services/core/java/com/android/server/biometrics/sensors/Interruptable.java @@ -37,10 +37,10 @@ public interface Interruptable { /** * Notifies the client that it needs to finish before - * {@link ClientMonitor#start(ClientMonitor.FinishCallback)} was invoked. This usually happens + * {@link ClientMonitor#start(ClientMonitor.Callback)} was invoked. This usually happens * if the client is still waiting in the pending queue and got notified that a subsequent * operation is preempting it. - * @param finishCallback invoked when the operation is completed. + * @param callback invoked when the operation is completed. */ - void cancelWithoutStarting(@NonNull ClientMonitor.FinishCallback finishCallback); + void cancelWithoutStarting(@NonNull ClientMonitor.Callback callback); } diff --git a/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java b/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java index 1c49bcdbadf4..1348f797a2dc 100644 --- a/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java @@ -55,8 +55,8 @@ public abstract class RemovalClient<T> extends ClientMonitor<T> implements Remov } @Override - public void start(@NonNull FinishCallback finishCallback) { - super.start(finishCallback); + public void start(@NonNull Callback callback) { + super.start(callback); // The biometric template ids will be removed when we get confirmation from the HAL startHalOperation(); @@ -85,7 +85,7 @@ public abstract class RemovalClient<T> extends ClientMonitor<T> implements Remov // cleanup). mAuthenticatorIds.put(getTargetUserId(), 0L); } - mFinishCallback.onClientFinished(this, true /* success */); + mCallback.onClientFinished(this, true /* success */); } } } diff --git a/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java index b78ee49826f2..5deb8fa26639 100644 --- a/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java @@ -36,10 +36,10 @@ public abstract class RevokeChallengeClient<T> extends ClientMonitor<T> { } @Override - public void start(@NonNull FinishCallback finishCallback) { - super.start(finishCallback); + public void start(@NonNull Callback callback) { + super.start(callback); startHalOperation(); - mFinishCallback.onClientFinished(this, true /* success */); + mCallback.onClientFinished(this, true /* success */); } } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/Face10.java index 6c57208c1e84..a4956cb56527 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/Face10.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/Face10.java @@ -98,6 +98,11 @@ class Face10 implements IHwBinder.DeathRecipient { @Nullable private IBiometricsFace mDaemon; private int mCurrentUserId = UserHandle.USER_NULL; + // If a challenge is generated, keep track of its owner. Since IBiometricsFace@1.0 only + // supports a single in-flight challenge, we must notify the interrupted owner that its + // challenge is no longer valid. The interrupted owner will be notified when the interrupter + // has finished. + @Nullable private FaceGenerateChallengeClient mCurrentChallengeOwner; private final UserSwitchObserver mUserSwitchObserver = new SynchronousUserSwitchObserver() { @Override @@ -394,9 +399,12 @@ class Face10 implements IHwBinder.DeathRecipient { final FaceUpdateActiveUserClient client = new FaceUpdateActiveUserClient(mContext, mLazyDaemon, targetUserId, mContext.getOpPackageName(), mSensorId, mCurrentUserId, hasEnrolled, mAuthenticatorIds); - mScheduler.scheduleClientMonitor(client, (clientMonitor, success) -> { - if (success) { - mCurrentUserId = targetUserId; + mScheduler.scheduleClientMonitor(client, new ClientMonitor.Callback() { + @Override + public void onClientFinished(@NonNull ClientMonitor<?> clientMonitor, boolean success) { + if (success) { + mCurrentUserId = targetUserId; + } } }); } @@ -459,18 +467,68 @@ class Face10 implements IHwBinder.DeathRecipient { void scheduleGenerateChallenge(@NonNull IBinder token, @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName) { mHandler.post(() -> { + if (mCurrentChallengeOwner != null) { + Slog.w(TAG, "Current challenge owner: " + mCurrentChallengeOwner + + ", interrupted by: " + opPackageName); + try { + mCurrentChallengeOwner.getListener().onChallengeInterrupted(mSensorId); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to notify challenge interrupted", e); + } + } + final FaceGenerateChallengeClient client = new FaceGenerateChallengeClient(mContext, mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), opPackageName, - mSensorId); - mScheduler.scheduleClientMonitor(client); + mSensorId, mCurrentChallengeOwner); + mScheduler.scheduleClientMonitor(client, new ClientMonitor.Callback() { + @Override + public void onClientStarted(@NonNull ClientMonitor<?> clientMonitor) { + if (client != clientMonitor) { + Slog.e(TAG, "scheduleGenerateChallenge, mismatched client." + + " Expecting: " + client + ", received: " + clientMonitor); + return; + } + Slog.d(TAG, "Current challenge owner: " + client); + mCurrentChallengeOwner = client; + } + }); }); } void scheduleRevokeChallenge(@NonNull IBinder token, @NonNull String owner) { mHandler.post(() -> { + if (!mCurrentChallengeOwner.getOwnerString().contentEquals(owner)) { + Slog.e(TAG, "Package: " + owner + " attempting to revoke challenge owned by: " + + mCurrentChallengeOwner.getOwnerString()); + return; + } + final FaceRevokeChallengeClient client = new FaceRevokeChallengeClient(mContext, mLazyDaemon, token, owner, mSensorId); - mScheduler.scheduleClientMonitor(client); + mScheduler.scheduleClientMonitor(client, new ClientMonitor.Callback() { + @Override + public void onClientFinished(@NonNull ClientMonitor<?> clientMonitor, + boolean success) { + if (client != clientMonitor) { + Slog.e(TAG, "scheduleRevokeChallenge, mismatched client." + + "Expecting: " + client + ", received: " + clientMonitor); + return; + } + + final FaceGenerateChallengeClient previousChallengeOwner = + mCurrentChallengeOwner.getInterruptedClient(); + mCurrentChallengeOwner = null; + Slog.d(TAG, "Previous challenge owner: " + previousChallengeOwner); + if (previousChallengeOwner != null) { + try { + previousChallengeOwner.getListener() + .onChallengeInterruptFinished(mSensorId); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to notify interrupt finished", e); + } + } + } + }); }); } @@ -488,12 +546,16 @@ class Face10 implements IHwBinder.DeathRecipient { opPackageName, FaceUtils.getInstance(), disabledFeatures, ENROLL_TIMEOUT_SEC, surfaceHandle, mSensorId); - mScheduler.scheduleClientMonitor(client, ((clientMonitor, success) -> { - if (success) { - // Update authenticatorIds - scheduleUpdateActiveUserWithoutHandler(client.getTargetUserId()); + mScheduler.scheduleClientMonitor(client, new ClientMonitor.Callback() { + @Override + public void onClientFinished(@NonNull ClientMonitor<?> clientMonitor, + boolean success) { + if (success) { + // Update authenticatorIds + scheduleUpdateActiveUserWithoutHandler(client.getTargetUserId()); + } } - })); + }); }); } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticationClient.java index 21bda74bc6b9..892d6a48488d 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticationClient.java @@ -92,7 +92,7 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> { } catch (RemoteException e) { Slog.e(TAG, "Remote exception when requesting auth", e); onError(BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */); - mFinishCallback.onClientFinished(this, false /* success */); + mCallback.onClientFinished(this, false /* success */); } } @@ -103,7 +103,7 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> { } catch (RemoteException e) { Slog.e(TAG, "Remote exception when requesting cancel", e); onError(BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */); - mFinishCallback.onClientFinished(this, false /* success */); + mCallback.onClientFinished(this, false /* success */); } } @@ -131,7 +131,7 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> { // 1) Authenticated == true // 2) Error occurred // 3) Authenticated == false - mFinishCallback.onClientFinished(this, true /* success */); + mCallback.onClientFinished(this, true /* success */); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceEnrollClient.java index 52a822675c2f..3e843cae96fd 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceEnrollClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceEnrollClient.java @@ -116,12 +116,12 @@ public class FaceEnrollClient extends EnrollClient<IBiometricsFace> { } if (status != Status.OK) { onError(BiometricFaceConstants.FACE_ERROR_UNABLE_TO_PROCESS, 0 /* vendorCode */); - mFinishCallback.onClientFinished(this, false /* success */); + mCallback.onClientFinished(this, false /* success */); } } catch (RemoteException e) { Slog.e(TAG, "Remote exception when requesting enroll", e); onError(BiometricFaceConstants.FACE_ERROR_UNABLE_TO_PROCESS, 0 /* vendorCode */); - mFinishCallback.onClientFinished(this, false /* success */); + mCallback.onClientFinished(this, false /* success */); } } @@ -132,7 +132,7 @@ public class FaceEnrollClient extends EnrollClient<IBiometricsFace> { } catch (RemoteException e) { Slog.e(TAG, "Remote exception when requesting cancel", e); onError(BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */); - mFinishCallback.onClientFinished(this, false /* success */); + mCallback.onClientFinished(this, false /* success */); } } } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceGenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceGenerateChallengeClient.java index 67f2712d0b9d..ba401f255e43 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceGenerateChallengeClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceGenerateChallengeClient.java @@ -17,12 +17,14 @@ package com.android.server.biometrics.sensors.face; import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.hardware.biometrics.face.V1_0.IBiometricsFace; import android.os.IBinder; import android.os.RemoteException; import android.util.Slog; +import com.android.server.biometrics.sensors.ClientMonitor; import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; import com.android.server.biometrics.sensors.GenerateChallengeClient; @@ -36,10 +38,22 @@ public class FaceGenerateChallengeClient extends GenerateChallengeClient<IBiomet private static final String TAG = "FaceGenerateChallengeClient"; private static final int CHALLENGE_TIMEOUT_SEC = 600; // 10 minutes + // If `this` FaceGenerateChallengeClient was invoked while an existing in-flight challenge + // was not revoked yet, store a reference to the interrupted client here. Notify the interrupted + // client when `this` challenge is revoked. + @Nullable private final FaceGenerateChallengeClient mInterruptedClient; + FaceGenerateChallengeClient(@NonNull Context context, @NonNull LazyDaemon<IBiometricsFace> lazyDaemon, @NonNull IBinder token, - @NonNull ClientMonitorCallbackConverter listener, @NonNull String owner, int sensorId) { + @NonNull ClientMonitorCallbackConverter listener, @NonNull String owner, int sensorId, + @Nullable FaceGenerateChallengeClient interruptedClient) { super(context, lazyDaemon, token, listener, owner, sensorId); + mInterruptedClient = interruptedClient; + } + + @Nullable + public FaceGenerateChallengeClient getInterruptedClient() { + return mInterruptedClient; } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceGetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceGetFeatureClient.java index ce57cb7686ed..8c7b99d6eb52 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceGetFeatureClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceGetFeatureClient.java @@ -61,8 +61,8 @@ public class FaceGetFeatureClient extends ClientMonitor<IBiometricsFace> { } @Override - public void start(@NonNull FinishCallback finishCallback) { - super.start(finishCallback); + public void start(@NonNull Callback callback) { + super.start(callback); startHalOperation(); } @@ -71,10 +71,10 @@ public class FaceGetFeatureClient extends ClientMonitor<IBiometricsFace> { try { final OptionalBool result = getFreshDaemon().getFeature(mFeature, mFaceId); getListener().onFeatureGet(result.status == Status.OK, mFeature, result.value); - mFinishCallback.onClientFinished(this, true /* success */); + mCallback.onClientFinished(this, true /* success */); } catch (RemoteException e) { Slog.e(TAG, "Unable to getFeature", e); - mFinishCallback.onClientFinished(this, false /* success */); + mCallback.onClientFinished(this, false /* success */); } } } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceInternalEnumerateClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceInternalEnumerateClient.java index f25242ee9b85..32d48321428a 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceInternalEnumerateClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceInternalEnumerateClient.java @@ -52,7 +52,7 @@ class FaceInternalEnumerateClient extends InternalEnumerateClient<IBiometricsFac getFreshDaemon().enumerate(); } catch (RemoteException e) { Slog.e(TAG, "Remote exception when requesting enumerate", e); - mFinishCallback.onClientFinished(this, false /* success */); + mCallback.onClientFinished(this, false /* success */); } } } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceRemovalClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceRemovalClient.java index 00d5f500b241..dde5ababd6c0 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceRemovalClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceRemovalClient.java @@ -51,7 +51,7 @@ class FaceRemovalClient extends RemovalClient<IBiometricsFace> { getFreshDaemon().remove(mBiometricId); } catch (RemoteException e) { Slog.e(TAG, "Remote exception when requesting remove", e); - mFinishCallback.onClientFinished(this, false /* success */); + mCallback.onClientFinished(this, false /* success */); } } } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceResetLockoutClient.java index 69070da0491e..f4324bedb4c6 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceResetLockoutClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceResetLockoutClient.java @@ -56,8 +56,8 @@ public class FaceResetLockoutClient extends ClientMonitor<IBiometricsFace> { } @Override - public void start(@NonNull FinishCallback finishCallback) { - super.start(finishCallback); + public void start(@NonNull Callback callback) { + super.start(callback); startHalOperation(); } @@ -65,10 +65,10 @@ public class FaceResetLockoutClient extends ClientMonitor<IBiometricsFace> { protected void startHalOperation() { try { getFreshDaemon().resetLockout(mHardwareAuthToken); - mFinishCallback.onClientFinished(this, true /* success */); + mCallback.onClientFinished(this, true /* success */); } catch (RemoteException e) { Slog.e(TAG, "Unable to reset lockout", e); - mFinishCallback.onClientFinished(this, false /* success */); + mCallback.onClientFinished(this, false /* success */); } } } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceSetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceSetFeatureClient.java index e7d041a11ccb..94abb7f378df 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceSetFeatureClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceSetFeatureClient.java @@ -70,8 +70,8 @@ public class FaceSetFeatureClient extends ClientMonitor<IBiometricsFace> { } @Override - public void start(@NonNull FinishCallback finishCallback) { - super.start(finishCallback); + public void start(@NonNull Callback callback) { + super.start(callback); startHalOperation(); } @@ -82,10 +82,10 @@ public class FaceSetFeatureClient extends ClientMonitor<IBiometricsFace> { final int result = getFreshDaemon() .setFeature(mFeature, mEnabled, mHardwareAuthToken, mFaceId); getListener().onFeatureSet(result == Status.OK, mFeature); - mFinishCallback.onClientFinished(this, true /* success */); + mCallback.onClientFinished(this, true /* success */); } catch (RemoteException e) { Slog.e(TAG, "Unable to set feature: " + mFeature + " to enabled: " + mEnabled, e); - mFinishCallback.onClientFinished(this, false /* success */); + mCallback.onClientFinished(this, false /* success */); } } } diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceUpdateActiveUserClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceUpdateActiveUserClient.java index bcf304e47816..05b176d28e28 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/FaceUpdateActiveUserClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceUpdateActiveUserClient.java @@ -50,8 +50,8 @@ public class FaceUpdateActiveUserClient extends ClientMonitor<IBiometricsFace> { } @Override - public void start(@NonNull FinishCallback finishCallback) { - super.start(finishCallback); + public void start(@NonNull Callback callback) { + super.start(callback); if (mCurrentUserId == getTargetUserId()) { Slog.d(TAG, "Already user: " + mCurrentUserId + ", refreshing authenticatorId"); @@ -61,7 +61,7 @@ public class FaceUpdateActiveUserClient extends ClientMonitor<IBiometricsFace> { } catch (RemoteException e) { Slog.e(TAG, "Unable to refresh authenticatorId", e); } - finishCallback.onClientFinished(this, true /* success */); + callback.onClientFinished(this, true /* success */); return; } @@ -79,16 +79,16 @@ public class FaceUpdateActiveUserClient extends ClientMonitor<IBiometricsFace> { FACE_DATA_DIR); if (!storePath.exists()) { Slog.e(TAG, "vold has not created the directory?"); - mFinishCallback.onClientFinished(this, false /* success */); + mCallback.onClientFinished(this, false /* success */); return; } try { getFreshDaemon().setActiveUser(getTargetUserId(), storePath.getAbsolutePath()); - mFinishCallback.onClientFinished(this, true /* success */); + mCallback.onClientFinished(this, true /* success */); } catch (RemoteException e) { Slog.e(TAG, "Failed to setActiveUser: " + e); - mFinishCallback.onClientFinished(this, false /* success */); + mCallback.onClientFinished(this, false /* success */); } } } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21.java index dad038626762..20a180712b5b 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21.java @@ -409,9 +409,12 @@ class Fingerprint21 implements IHwBinder.DeathRecipient { new FingerprintUpdateActiveUserClient(mContext, mLazyDaemon, targetUserId, mContext.getOpPackageName(), mSensorProperties.sensorId, mCurrentUserId, hasEnrolled, mAuthenticatorIds); - mScheduler.scheduleClientMonitor(client, (clientMonitor, success) -> { - if (success) { - mCurrentUserId = targetUserId; + mScheduler.scheduleClientMonitor(client, new ClientMonitor.Callback() { + @Override + public void onClientFinished(@NonNull ClientMonitor<?> clientMonitor, boolean success) { + if (success) { + mCurrentUserId = targetUserId; + } } }); } @@ -453,12 +456,16 @@ class Fingerprint21 implements IHwBinder.DeathRecipient { mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken, opPackageName, FingerprintUtils.getInstance(), ENROLL_TIMEOUT_SEC, mSensorProperties.sensorId, mUdfpsOverlayController); - mScheduler.scheduleClientMonitor(client, ((clientMonitor, success) -> { - if (success) { - // Update authenticatorIds - scheduleUpdateActiveUserWithoutHandler(clientMonitor.getTargetUserId()); + mScheduler.scheduleClientMonitor(client, new ClientMonitor.Callback() { + @Override + public void onClientFinished(@NonNull ClientMonitor<?> clientMonitor, + boolean success) { + if (success) { + // Update authenticatorIds + scheduleUpdateActiveUserWithoutHandler(clientMonitor.getTargetUserId()); + } } - })); + }); }); } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticationClient.java index 1564056cfdbd..751df8ef9925 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticationClient.java @@ -79,7 +79,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi if (authenticated) { resetFailedAttempts(getTargetUserId()); UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController); - mFinishCallback.onClientFinished(this, true /* success */); + mCallback.onClientFinished(this, true /* success */); } else { final @LockoutTracker.LockoutMode int lockoutMode = mLockoutFrameworkImpl.getLockoutModeForUser(getTargetUserId()); @@ -119,7 +119,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */); UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController); - mFinishCallback.onClientFinished(this, false /* success */); + mCallback.onClientFinished(this, false /* success */); } } @@ -132,7 +132,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi Slog.e(TAG, "Remote exception when requesting cancel", e); onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */); - mFinishCallback.onClientFinished(this, false /* success */); + mCallback.onClientFinished(this, false /* success */); } } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintDetectClient.java index 8b295f8f4931..8652ee403089 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintDetectClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintDetectClient.java @@ -68,13 +68,13 @@ class FingerprintDetectClient extends AcquisitionClient<IBiometricsFingerprint> Slog.e(TAG, "Remote exception when requesting cancel", e); onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */); - mFinishCallback.onClientFinished(this, false /* success */); + mCallback.onClientFinished(this, false /* success */); } } @Override - public void start(@NonNull FinishCallback finishCallback) { - super.start(finishCallback); + public void start(@NonNull Callback callback) { + super.start(callback); startHalOperation(); } @@ -88,7 +88,7 @@ class FingerprintDetectClient extends AcquisitionClient<IBiometricsFingerprint> onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */); UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController); - mFinishCallback.onClientFinished(this, false /* success */); + mCallback.onClientFinished(this, false /* success */); } } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintEnrollClient.java index 32f8b8fe8b26..d5db6e411b95 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintEnrollClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintEnrollClient.java @@ -79,7 +79,7 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */); UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController); - mFinishCallback.onClientFinished(this, false /* success */); + mCallback.onClientFinished(this, false /* success */); } } @@ -92,7 +92,7 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint Slog.e(TAG, "Remote exception when requesting cancel", e); onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */); - mFinishCallback.onClientFinished(this, false /* success */); + mCallback.onClientFinished(this, false /* success */); } } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintInternalEnumerateClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintInternalEnumerateClient.java index 240c3c56f75e..834bf42eba3f 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintInternalEnumerateClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintInternalEnumerateClient.java @@ -52,7 +52,7 @@ class FingerprintInternalEnumerateClient extends InternalEnumerateClient<IBiomet getFreshDaemon().enumerate(); } catch (RemoteException e) { Slog.e(TAG, "Remote exception when requesting enumerate", e); - mFinishCallback.onClientFinished(this, false /* success */); + mCallback.onClientFinished(this, false /* success */); } } } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintRemovalClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintRemovalClient.java index a9336ef6a6c2..9f5456300884 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintRemovalClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintRemovalClient.java @@ -54,7 +54,7 @@ class FingerprintRemovalClient extends RemovalClient<IBiometricsFingerprint> { getFreshDaemon().remove(getTargetUserId(), mBiometricId); } catch (RemoteException e) { Slog.e(TAG, "Remote exception when requesting remove", e); - mFinishCallback.onClientFinished(this, false /* success */); + mCallback.onClientFinished(this, false /* success */); } } } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUpdateActiveUserClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUpdateActiveUserClient.java index e1082ae51575..c1c3593db564 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUpdateActiveUserClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUpdateActiveUserClient.java @@ -22,7 +22,6 @@ import android.hardware.biometrics.BiometricsProtoEnums; import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint; import android.os.Build; import android.os.Environment; -import android.os.IBinder; import android.os.RemoteException; import android.os.SELinux; import android.util.Slog; @@ -58,8 +57,8 @@ public class FingerprintUpdateActiveUserClient extends ClientMonitor<IBiometrics } @Override - public void start(@NonNull FinishCallback finishCallback) { - super.start(finishCallback); + public void start(@NonNull Callback callback) { + super.start(callback); if (mCurrentUserId == getTargetUserId()) { Slog.d(TAG, "Already user: " + mCurrentUserId + ", refreshing authenticatorId"); @@ -69,7 +68,7 @@ public class FingerprintUpdateActiveUserClient extends ClientMonitor<IBiometrics } catch (RemoteException e) { Slog.e(TAG, "Unable to refresh authenticatorId", e); } - finishCallback.onClientFinished(this, true /* success */); + callback.onClientFinished(this, true /* success */); return; } @@ -89,7 +88,7 @@ public class FingerprintUpdateActiveUserClient extends ClientMonitor<IBiometrics if (!mDirectory.exists()) { if (!mDirectory.mkdir()) { Slog.e(TAG, "Cannot make directory: " + mDirectory.getAbsolutePath()); - finishCallback.onClientFinished(this, false /* success */); + callback.onClientFinished(this, false /* success */); return; } // Calling mkdir() from this process will create a directory with our @@ -97,7 +96,7 @@ public class FingerprintUpdateActiveUserClient extends ClientMonitor<IBiometrics // the label. if (!SELinux.restorecon(mDirectory)) { Slog.e(TAG, "Restorecons failed. Directory will have wrong label."); - finishCallback.onClientFinished(this, false /* success */); + callback.onClientFinished(this, false /* success */); return; } } @@ -116,10 +115,10 @@ public class FingerprintUpdateActiveUserClient extends ClientMonitor<IBiometrics getFreshDaemon().setActiveGroup(getTargetUserId(), mDirectory.getAbsolutePath()); mAuthenticatorIds.put(getTargetUserId(), mHasEnrolledBiometrics ? getFreshDaemon().getAuthenticatorId() : 0L); - mFinishCallback.onClientFinished(this, true /* success */); + mCallback.onClientFinished(this, true /* success */); } catch (RemoteException e) { Slog.e(TAG, "Failed to setActiveGroup: " + e); - mFinishCallback.onClientFinished(this, false /* success */); + mCallback.onClientFinished(this, false /* success */); } } } diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java index 7202f0f401f9..7f9b3c9fcff7 100644 --- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java +++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java @@ -56,7 +56,6 @@ import android.system.OsConstants; import android.util.ArraySet; import android.util.Log; import android.util.SparseArray; -import android.util.SparseIntArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -130,7 +129,42 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse } } - public PermissionMonitor(@NonNull final Context context, @NonNull final INetd netd) { + /** + * A data class to store each uid Netd permission information. Netd permissions includes + * PERMISSION_NETWORK, PERMISSION_SYSTEM, PERMISSION_INTERNET, PERMISSION_UPDATE_DEVICE_STATS + * and OR'd with the others. Default permission is PERMISSION_NONE and PERMISSION_UNINSTALLED + * will be set if all packages are removed from the uid. + */ + public static class UidNetdPermissionInfo { + private final int mNetdPermissions; + + UidNetdPermissionInfo() { + this(PERMISSION_NONE); + } + + UidNetdPermissionInfo(int permissions) { + mNetdPermissions = permissions; + } + + /** Plus given permissions and return new UidNetdPermissionInfo instance. */ + public UidNetdPermissionInfo plusNetdPermissions(int permissions) { + return new UidNetdPermissionInfo(mNetdPermissions | permissions); + } + + /** Return whether package is uninstalled. */ + public boolean isPackageUninstalled() { + return mNetdPermissions == PERMISSION_UNINSTALLED; + } + + /** Check that uid has given permissions */ + public boolean hasNetdPermissions(final int permissions) { + if (isPackageUninstalled()) return false; + if (permissions == PERMISSION_NONE) return true; + return (mNetdPermissions & permissions) == permissions; + } + } + + public PermissionMonitor(Context context, INetd netd) { this(context, netd, new Dependencies()); } @@ -161,7 +195,7 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse return; } - SparseIntArray netdPermsUids = new SparseIntArray(); + final SparseArray<UidNetdPermissionInfo> netdPermsUids = new SparseArray<>(); for (PackageInfo app : apps) { int uid = app.applicationInfo != null ? app.applicationInfo.uid : INVALID_UID; @@ -183,9 +217,13 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse } } + // Skip already checked uid. + if (netdPermsUids.get(uid) != null) continue; + //TODO: unify the management of the permissions into one codepath. - final int otherNetdPerms = getNetdPermissionMask(uid); - netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms); + final UidNetdPermissionInfo permInfo = + new UidNetdPermissionInfo(getNetdPermissionMask(uid)); + netdPermsUids.put(uid, permInfo); } List<UserInfo> users = mUserManager.getUsers(true); // exclude dying users @@ -207,7 +245,10 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse ? PERMISSION_UPDATE_DEVICE_STATS : 0; netdPermission |= perms.contains(INTERNET) ? PERMISSION_INTERNET : 0; } - netdPermsUids.put(uid, netdPermsUids.get(uid) | netdPermission); + final UidNetdPermissionInfo permInfo = netdPermsUids.get(uid); + netdPermsUids.put(uid, permInfo != null + ? permInfo.plusNetdPermissions(netdPermission) + : new UidNetdPermissionInfo(netdPermission)); } log("Users: " + mUsers.size() + ", Apps: " + mApps.size()); update(mUsers, mApps, true); @@ -341,15 +382,15 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse return currentPermission; } - private int getPermissionForUid(final int uid) { + private UidNetdPermissionInfo getPermissionForUid(final int uid) { // Check all the packages for this UID. The UID has the permission if any of the // packages in it has the permission. final String[] packages = mPackageManager.getPackagesForUid(uid); if (packages == null || packages.length <= 0) { // The last package of this uid is removed from device. Clean the package up. - return PERMISSION_UNINSTALLED; + return new UidNetdPermissionInfo(PERMISSION_UNINSTALLED); } - return getNetdPermissionMask(uid); + return new UidNetdPermissionInfo(getNetdPermissionMask(uid)); } /** @@ -599,28 +640,28 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse * permission information to netd. * * @param uid the app uid of the package installed - * @param permissions the permissions the app requested and netd cares about. + * @param permissionInfo the permission info of given uid. * * @hide */ @VisibleForTesting - void sendPackagePermissionsForUid(int uid, int permissions) { - SparseIntArray netdPermissionsAppIds = new SparseIntArray(); - netdPermissionsAppIds.put(uid, permissions); - sendPackagePermissionsToNetd(netdPermissionsAppIds); + void sendPackagePermissionsForUid(int uid, UidNetdPermissionInfo permissionInfo) { + final SparseArray<UidNetdPermissionInfo> uidsPermInfo = new SparseArray<>(); + uidsPermInfo.put(uid, permissionInfo); + sendPackagePermissionsToNetd(uidsPermInfo); } /** * Called by packageManagerService to send IPC to netd. Grant or revoke the INTERNET * and/or UPDATE_DEVICE_STATS permission of the uids in array. * - * @param netdPermissionsAppIds integer pairs of uids and the permission granted to it. If the - * permission is 0, revoke all permissions of that uid. - * + * @param uidsPermInfo permission info array generated from each uid. If the uid permission is + * PERMISSION_NONE or PERMISSION_UNINSTALLED, revoke all permissions of that + * uid. * @hide */ @VisibleForTesting - void sendPackagePermissionsToNetd(SparseIntArray netdPermissionsAppIds) { + void sendPackagePermissionsToNetd(final SparseArray<UidNetdPermissionInfo> uidsPermInfo) { if (mNetd == null) { Log.e(TAG, "Failed to get the netd service"); return; @@ -630,26 +671,20 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse ArrayList<Integer> updateStatsPermissionAppIds = new ArrayList<>(); ArrayList<Integer> noPermissionAppIds = new ArrayList<>(); ArrayList<Integer> uninstalledAppIds = new ArrayList<>(); - for (int i = 0; i < netdPermissionsAppIds.size(); i++) { - int permissions = netdPermissionsAppIds.valueAt(i); - switch(permissions) { - case (PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS): - allPermissionAppIds.add(netdPermissionsAppIds.keyAt(i)); - break; - case PERMISSION_INTERNET: - internetPermissionAppIds.add(netdPermissionsAppIds.keyAt(i)); - break; - case PERMISSION_UPDATE_DEVICE_STATS: - updateStatsPermissionAppIds.add(netdPermissionsAppIds.keyAt(i)); - break; - case PERMISSION_NONE: - noPermissionAppIds.add(netdPermissionsAppIds.keyAt(i)); - break; - case PERMISSION_UNINSTALLED: - uninstalledAppIds.add(netdPermissionsAppIds.keyAt(i)); - default: - Log.e(TAG, "unknown permission type: " + permissions + "for uid: " - + netdPermissionsAppIds.keyAt(i)); + for (int i = 0; i < uidsPermInfo.size(); i++) { + final int uid = uidsPermInfo.keyAt(i); + final UidNetdPermissionInfo permInfo = uidsPermInfo.valueAt(i); + if (permInfo.hasNetdPermissions( + PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS)) { + allPermissionAppIds.add(uid); + } else if (permInfo.hasNetdPermissions(PERMISSION_INTERNET)) { + internetPermissionAppIds.add(uid); + } else if (permInfo.hasNetdPermissions(PERMISSION_UPDATE_DEVICE_STATS)) { + updateStatsPermissionAppIds.add(uid); + } else if (permInfo.isPackageUninstalled()) { + uninstalledAppIds.add(uid); + } else { + noPermissionAppIds.add(uid); } } try { diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 1c93d4eb599b..5484bfca5851 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -153,8 +153,8 @@ public class Vpn { private static final boolean LOGD = true; // Length of time (in milliseconds) that an app hosting an always-on VPN is placed on - // the device idle whitelist during service launch and VPN bootstrap. - private static final long VPN_LAUNCH_IDLE_WHITELIST_DURATION_MS = 60 * 1000; + // the device idle allowlist during service launch and VPN bootstrap. + private static final long VPN_LAUNCH_IDLE_ALLOWLIST_DURATION_MS = 60 * 1000; // Settings for how much of the address space should be routed so that Vpn considers // "most" of the address space is routed. This is used to determine whether this Vpn @@ -180,7 +180,8 @@ public class Vpn { // This is taken as a total of IPv4 + IPV6 routes for simplicity, but the algorithm // is actually O(n²)+O(n²). private static final int MAX_ROUTES_TO_EVALUATE = 150; - + private static final String LOCKDOWN_ALLOWLIST_SETTING_NAME = + Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST; /** * Largest profile size allowable for Platform VPNs. * @@ -236,7 +237,7 @@ public class Vpn { * Set of packages in addition to the VPN app itself that can access the network directly when * VPN is not connected even if {@code mLockdown} is set. */ - private @NonNull List<String> mLockdownWhitelist = Collections.emptyList(); + private @NonNull List<String> mLockdownAllowlist = Collections.emptyList(); /** * A memory of what UIDs this class told netd to block for the lockdown feature. @@ -520,7 +521,7 @@ public class Vpn { } } if (!hadUnderlyingNetworks) { - // No idea what the underlying networks are; assume sane defaults + // No idea what the underlying networks are; assume the safer defaults metered = true; roaming = false; congested = false; @@ -653,18 +654,18 @@ public class Vpn { * * @param packageName the package to designate as always-on VPN supplier. * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting. - * @param lockdownWhitelist packages to be whitelisted from lockdown. + * @param lockdownAllowlist packages to be allowed from lockdown. * @param keyStore the Keystore instance to use for checking of PlatformVpnProfile(s) * @return {@code true} if the package has been set as always-on, {@code false} otherwise. */ public synchronized boolean setAlwaysOnPackage( @Nullable String packageName, boolean lockdown, - @Nullable List<String> lockdownWhitelist, + @Nullable List<String> lockdownAllowlist, @NonNull KeyStore keyStore) { enforceControlPermissionOrInternalCaller(); - if (setAlwaysOnPackageInternal(packageName, lockdown, lockdownWhitelist, keyStore)) { + if (setAlwaysOnPackageInternal(packageName, lockdown, lockdownAllowlist, keyStore)) { saveAlwaysOnPackage(); return true; } @@ -679,7 +680,7 @@ public class Vpn { * * @param packageName the package to designate as always-on VPN supplier. * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting. - * @param lockdownWhitelist packages to be whitelisted from lockdown. This is only used if + * @param lockdownAllowlist packages to be allowed to bypass lockdown. This is only used if * {@code lockdown} is {@code true}. Packages must not contain commas. * @param keyStore the system keystore instance to check for profiles * @return {@code true} if the package has been set as always-on, {@code false} otherwise. @@ -687,16 +688,16 @@ public class Vpn { @GuardedBy("this") private boolean setAlwaysOnPackageInternal( @Nullable String packageName, boolean lockdown, - @Nullable List<String> lockdownWhitelist, @NonNull KeyStore keyStore) { + @Nullable List<String> lockdownAllowlist, @NonNull KeyStore keyStore) { if (VpnConfig.LEGACY_VPN.equals(packageName)) { Log.w(TAG, "Not setting legacy VPN \"" + packageName + "\" as always-on."); return false; } - if (lockdownWhitelist != null) { - for (String pkg : lockdownWhitelist) { + if (lockdownAllowlist != null) { + for (String pkg : lockdownAllowlist) { if (pkg.contains(",")) { - Log.w(TAG, "Not setting always-on vpn, invalid whitelisted package: " + pkg); + Log.w(TAG, "Not setting always-on vpn, invalid allowed package: " + pkg); return false; } } @@ -724,8 +725,8 @@ public class Vpn { } mLockdown = (mAlwaysOn && lockdown); - mLockdownWhitelist = (mLockdown && lockdownWhitelist != null) - ? Collections.unmodifiableList(new ArrayList<>(lockdownWhitelist)) + mLockdownAllowlist = (mLockdown && lockdownAllowlist != null) + ? Collections.unmodifiableList(new ArrayList<>(lockdownAllowlist)) : Collections.emptyList(); if (isCurrentPreparedPackage(packageName)) { @@ -754,10 +755,10 @@ public class Vpn { } /** - * @return an immutable list of packages whitelisted from always-on VPN lockdown. + * @return an immutable list of packages allowed to bypass always-on VPN lockdown. */ - public synchronized List<String> getLockdownWhitelist() { - return mLockdown ? mLockdownWhitelist : null; + public synchronized List<String> getLockdownAllowlist() { + return mLockdown ? mLockdownAllowlist : null; } /** @@ -772,8 +773,8 @@ public class Vpn { mSystemServices.settingsSecurePutIntForUser(Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, (mAlwaysOn && mLockdown ? 1 : 0), mUserHandle); mSystemServices.settingsSecurePutStringForUser( - Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST, - String.join(",", mLockdownWhitelist), mUserHandle); + LOCKDOWN_ALLOWLIST_SETTING_NAME, + String.join(",", mLockdownAllowlist), mUserHandle); } finally { Binder.restoreCallingIdentity(token); } @@ -788,12 +789,12 @@ public class Vpn { Settings.Secure.ALWAYS_ON_VPN_APP, mUserHandle); final boolean alwaysOnLockdown = mSystemServices.settingsSecureGetIntForUser( Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, 0 /*default*/, mUserHandle) != 0; - final String whitelistString = mSystemServices.settingsSecureGetStringForUser( - Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST, mUserHandle); - final List<String> whitelistedPackages = TextUtils.isEmpty(whitelistString) - ? Collections.emptyList() : Arrays.asList(whitelistString.split(",")); + final String allowlistString = mSystemServices.settingsSecureGetStringForUser( + LOCKDOWN_ALLOWLIST_SETTING_NAME, mUserHandle); + final List<String> allowedPackages = TextUtils.isEmpty(allowlistString) + ? Collections.emptyList() : Arrays.asList(allowlistString.split(",")); setAlwaysOnPackageInternal( - alwaysOnPackage, alwaysOnLockdown, whitelistedPackages, keyStore); + alwaysOnPackage, alwaysOnLockdown, allowedPackages, keyStore); } finally { Binder.restoreCallingIdentity(token); } @@ -849,7 +850,7 @@ public class Vpn { DeviceIdleInternal idleController = LocalServices.getService(DeviceIdleInternal.class); idleController.addPowerSaveTempWhitelistApp(Process.myUid(), alwaysOnPackage, - VPN_LAUNCH_IDLE_WHITELIST_DURATION_MS, mUserHandle, false, "vpn"); + VPN_LAUNCH_IDLE_ALLOWLIST_DURATION_MS, mUserHandle, false, "vpn"); // Start the VPN service declared in the app's manifest. Intent serviceIntent = new Intent(VpnConfig.SERVICE_INTERFACE); @@ -1212,7 +1213,7 @@ public class Vpn { // applications have changed. Consider diffing UID ranges and only applying the delta. if (!Objects.equals(oldConfig.allowedApplications, mConfig.allowedApplications) || !Objects.equals(oldConfig.disallowedApplications, mConfig.disallowedApplications)) { - Log.i(TAG, "Handover not possible due to changes to whitelisted/blacklisted apps"); + Log.i(TAG, "Handover not possible due to changes to allowed/denied apps"); return false; } @@ -1440,13 +1441,13 @@ public class Vpn { * associated with one user, and any restricted profiles attached to that user. * * <p>If one of {@param allowedApplications} or {@param disallowedApplications} is provided, - * the UID ranges will match the app whitelist or blacklist specified there. Otherwise, all UIDs + * the UID ranges will match the app list specified there. Otherwise, all UIDs * in each user and profile will be included. * * @param userHandle The userId to create UID ranges for along with any of its restricted * profiles. - * @param allowedApplications (optional) whitelist of applications to include. - * @param disallowedApplications (optional) blacklist of applications to exclude. + * @param allowedApplications (optional) List of applications to allow. + * @param disallowedApplications (optional) List of applications to deny. */ @VisibleForTesting Set<UidRange> createUserAndRestrictedProfilesRanges(@UserIdInt int userHandle, @@ -1480,13 +1481,13 @@ public class Vpn { * associated with one user. * * <p>If one of {@param allowedApplications} or {@param disallowedApplications} is provided, - * the UID ranges will match the app whitelist or blacklist specified there. Otherwise, all UIDs + * the UID ranges will match the app allowlist or denylist specified there. Otherwise, all UIDs * in the user will be included. * * @param ranges {@link Set} of {@link UidRange}s to which to add. * @param userHandle The userId to add to {@param ranges}. - * @param allowedApplications (optional) whitelist of applications to include. - * @param disallowedApplications (optional) blacklist of applications to exclude. + * @param allowedApplications (optional) allowlist of applications to include. + * @param disallowedApplications (optional) denylist of applications to exclude. */ @VisibleForTesting void addUserToRanges(@NonNull Set<UidRange> ranges, @UserIdInt int userHandle, @@ -1608,7 +1609,7 @@ public class Vpn { /** * Restricts network access from all UIDs affected by this {@link Vpn}, apart from the VPN - * service app itself and whitelisted packages, to only sockets that have had {@code protect()} + * service app itself and allowed packages, to only sockets that have had {@code protect()} * called on them. All non-VPN traffic is blocked via a {@code PROHIBIT} response from the * kernel. * @@ -1630,7 +1631,7 @@ public class Vpn { if (isNullOrLegacyVpn(mPackage)) { exemptedPackages = null; } else { - exemptedPackages = new ArrayList<>(mLockdownWhitelist); + exemptedPackages = new ArrayList<>(mLockdownAllowlist); exemptedPackages.add(mPackage); } final Set<UidRange> rangesToTellNetdToRemove = new ArraySet<>(mBlockedUidsAsToldToNetd); @@ -1675,7 +1676,7 @@ public class Vpn { * Tell netd to add or remove a list of {@link UidRange}s to the list of UIDs that are only * allowed to make connections through sockets that have had {@code protect()} called on them. * - * @param enforce {@code true} to add to the blacklist, {@code false} to remove. + * @param enforce {@code true} to add to the denylist, {@code false} to remove. * @param ranges {@link Collection} of {@link UidRange}s to add (if {@param enforce} is * {@code true}) or to remove. * @return {@code true} if all of the UIDs were added/removed. {@code false} otherwise, diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java index 05cf40a091b6..3ac95d71de3d 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java @@ -178,7 +178,7 @@ public abstract class InputMethodManagerInternal { }; /** - * @return Global instance if exists. Otherwise, a dummy no-op instance. + * @return Global instance if exists. Otherwise, a fallback no-op instance. */ @NonNull public static InputMethodManagerInternal get() { diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 3cd70fecbf3d..9ab410d258cc 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -2213,8 +2213,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub * @param client {@link android.os.Binder} proxy that is associated with the singleton instance * of {@link android.view.inputmethod.InputMethodManager} that runs on the client * process - * @param inputContext communication channel for the dummy - * {@link android.view.inputmethod.InputConnection} + * @param inputContext communication channel for the fallback {@link InputConnection} * @param selfReportedDisplayId self-reported display ID to which the client is associated. * Whether the client is still allowed to access to this display * or not needs to be evaluated every time the client interacts @@ -3451,9 +3450,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return InputBindResult.USER_SWITCHING; } - // Master feature flag that overrides other conditions and forces IME preRendering. + // Main feature flag that overrides other conditions and forces IME preRendering. if (DEBUG) { - Slog.v(TAG, "IME PreRendering MASTER flag: " + Slog.v(TAG, "IME PreRendering main flag: " + DebugFlags.FLAG_PRE_RENDER_IME_VIEWS.value() + ", LowRam: " + mIsLowRam); } // pre-rendering not supported on low-ram devices. diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java index 937514ca9139..b518eb1ab6d0 100644 --- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java @@ -1663,7 +1663,7 @@ public final class MultiClientInputMethodManagerService { } if (editorInfo == null) { - // So-called dummy InputConnection scenario. For app compatibility, we still + // So-called fallback InputConnection scenario. For app compatibility, we still // notify this to the IME. switch (clientInfo.mState) { case InputMethodClientState.READY_TO_SEND_FIRST_BIND_RESULT: diff --git a/services/core/java/com/android/server/location/LocationProviderManager.java b/services/core/java/com/android/server/location/LocationProviderManager.java index c3532a84c42d..05aa3150cfef 100644 --- a/services/core/java/com/android/server/location/LocationProviderManager.java +++ b/services/core/java/com/android/server/location/LocationProviderManager.java @@ -229,7 +229,7 @@ class LocationProviderManager extends // we cache these values because checking/calculating on the fly is more expensive private boolean mPermitted; private boolean mForeground; - @Nullable private LocationRequest mProviderLocationRequest; + private LocationRequest mProviderLocationRequest; private boolean mIsUsingHighPower; protected Registration(LocationRequest request, CallerIdentity identity, @@ -244,6 +244,8 @@ class LocationProviderManager extends } else { mWorkSource = identity.addToWorkSource(null); } + + mProviderLocationRequest = super.getRequest(); } @GuardedBy("mLock") @@ -313,7 +315,7 @@ class LocationProviderManager extends @Override public final LocationRequest getRequest() { - return Objects.requireNonNull(mProviderLocationRequest); + return mProviderLocationRequest; } public final boolean isForeground() { diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java index 81d07cc11527..e9a05a8aa16c 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java @@ -484,7 +484,7 @@ class LockSettingsStorage { public Map<Integer, List<Long>> listSyntheticPasswordHandlesForAllUsers(String stateName) { Map<Integer, List<Long>> result = new ArrayMap<>(); final UserManager um = UserManager.get(mContext); - for (UserInfo user : um.getUsers(false)) { + for (UserInfo user : um.getUsers()) { result.put(user.id, listSyntheticPasswordHandlesForUser(stateName, user.id)); } return result; diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 0f6748366e16..8777ceacf884 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -589,11 +589,19 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR if (mDestroyed) { return; } + ParceledListSlice<QueueItem> parcelableQueue; + if (mQueue == null) { + parcelableQueue = null; + } else { + parcelableQueue = new ParceledListSlice<>(mQueue); + // Limit the size of initial Parcel to prevent binder buffer overflow + // as onQueueChanged is an async binder call. + parcelableQueue.setInlineCountLimit(1); + } for (int i = mControllerCallbackHolders.size() - 1; i >= 0; i--) { ISessionControllerCallbackHolder holder = mControllerCallbackHolders.get(i); try { - holder.mCallback.onQueueChanged(mQueue == null ? null : - new ParceledListSlice<>(mQueue)); + holder.mCallback.onQueueChanged(parcelableQueue); } catch (DeadObjectException e) { mControllerCallbackHolders.remove(i); logCallbackException("Removing dead callback in pushQueueUpdate", holder, e); diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java index eb4ab1ceac28..a8a0e2e937d0 100644 --- a/services/core/java/com/android/server/media/MediaSessionService.java +++ b/services/core/java/com/android/server/media/MediaSessionService.java @@ -32,14 +32,15 @@ import android.app.KeyguardManager; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.ActivityNotFoundException; +import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.content.pm.UserInfo; -import android.database.ContentObserver; import android.media.AudioManager; import android.media.AudioManagerInternal; import android.media.AudioPlaybackConfiguration; @@ -58,7 +59,6 @@ import android.media.session.ISessionManager; import android.media.session.MediaController; import android.media.session.MediaSession; import android.media.session.MediaSessionManager; -import android.net.Uri; import android.os.Binder; import android.os.Bundle; import android.os.Handler; @@ -138,7 +138,6 @@ public class MediaSessionService extends SystemService implements Monitor { private KeyguardManager mKeyguardManager; private AudioManagerInternal mAudioManagerInternal; private ContentResolver mContentResolver; - private SettingsObserver mSettingsObserver; private boolean mHasFeatureLeanback; // The FullUserRecord of the current users. (i.e. The foreground user that isn't a profile) @@ -192,8 +191,6 @@ public class MediaSessionService extends SystemService implements Monitor { } }, null /* handler */); mContentResolver = mContext.getContentResolver(); - mSettingsObserver = new SettingsObserver(); - mSettingsObserver.observe(); mHasFeatureLeanback = mContext.getPackageManager().hasSystemFeature( PackageManager.FEATURE_LEANBACK); @@ -202,8 +199,20 @@ public class MediaSessionService extends SystemService implements Monitor { instantiateCustomProvider(null); instantiateCustomDispatcher(null); mRecordThread.start(); + + final IntentFilter filter = new IntentFilter( + NotificationManager.ACTION_NOTIFICATION_LISTENER_ENABLED_CHANGED); + mContext.registerReceiver(mNotificationListenerEnabledChangedReceiver, filter); } + private final BroadcastReceiver mNotificationListenerEnabledChangedReceiver = + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + updateActiveSessionListeners(); + } + }; + private boolean isGlobalPriorityActiveLocked() { return mGlobalPrioritySession != null && mGlobalPrioritySession.isActive(); } @@ -1082,25 +1091,6 @@ public class MediaSessionService extends SystemService implements Monitor { } } - final class SettingsObserver extends ContentObserver { - private final Uri mSecureSettingsUri = Settings.Secure.getUriFor( - Settings.Secure.ENABLED_NOTIFICATION_LISTENERS); - - private SettingsObserver() { - super(null); - } - - private void observe() { - mContentResolver.registerContentObserver(mSecureSettingsUri, - false, this, ALL.getIdentifier()); - } - - @Override - public void onChange(boolean selfChange, Uri uri) { - updateActiveSessionListeners(); - } - } - class SessionManagerImpl extends ISessionManager.Stub { private static final String EXTRA_WAKELOCK_ACQUIRED = "android.media.AudioService.WAKELOCK_ACQUIRED"; @@ -2710,5 +2700,4 @@ public class MediaSessionService extends SystemService implements Monitor { obtainMessage(msg, userIdInteger).sendToTarget(); } } - } diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java index 953aae44d6a7..d9b5b6d41c11 100644 --- a/services/core/java/com/android/server/media/MediaSessionStack.java +++ b/services/core/java/com/android/server/media/MediaSessionStack.java @@ -20,7 +20,6 @@ import static com.android.server.media.SessionPolicyProvider.SESSION_POLICY_IGNO import android.media.Session2Token; import android.media.session.MediaSession; -import android.os.Debug; import android.os.UserHandle; import android.util.Log; import android.util.SparseArray; @@ -187,7 +186,7 @@ class MediaSessionStack { */ public void updateMediaButtonSessionIfNeeded() { if (DEBUG) { - Log.d(TAG, "updateMediaButtonSessionIfNeeded, callers=" + Debug.getCallers(2)); + Log.d(TAG, "updateMediaButtonSessionIfNeeded, callers=" + getCallers(2)); } List<Integer> audioPlaybackUids = mAudioPlayerStateMonitor.getSortedAudioPlaybackClientUids(); @@ -413,4 +412,24 @@ class MediaSessionStack { // so they also need to be cleared. mCachedActiveLists.remove(UserHandle.USER_ALL); } + + // Code copied from android.os.Debug#getCallers(int) + private static String getCallers(final int depth) { + final StackTraceElement[] callStack = Thread.currentThread().getStackTrace(); + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < depth; i++) { + sb.append(getCaller(callStack, i)).append(" "); + } + return sb.toString(); + } + + // Code copied from android.os.Debug#getCaller(StackTraceElement[], int) + private static String getCaller(StackTraceElement[] callStack, int depth) { + // callStack[4] is the caller of the method that called getCallers() + if (4 + depth >= callStack.length) { + return "<bottom of call stack>"; + } + StackTraceElement caller = callStack[4 + depth]; + return caller.getClassName() + "." + caller.getMethodName() + ":" + caller.getLineNumber(); + } } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 2d052da22714..9f9235dc852f 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -31,6 +31,7 @@ import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL; import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED; import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED; +import static android.app.NotificationManager.ACTION_NOTIFICATION_LISTENER_ENABLED_CHANGED; import static android.app.NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED; import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL; import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_ID; @@ -7758,6 +7759,13 @@ public class NotificationManagerService extends SystemService { @VisibleForTesting void updateUriPermissions(@Nullable NotificationRecord newRecord, @Nullable NotificationRecord oldRecord, String targetPkg, int targetUserId) { + updateUriPermissions(newRecord, oldRecord, targetPkg, targetUserId, false); + } + + @VisibleForTesting + void updateUriPermissions(@Nullable NotificationRecord newRecord, + @Nullable NotificationRecord oldRecord, String targetPkg, int targetUserId, + boolean onlyRevokeCurrentTarget) { final String key = (newRecord != null) ? newRecord.getKey() : oldRecord.getKey(); if (DBG) Slog.d(TAG, key + ": updating permissions"); @@ -7785,7 +7793,9 @@ public class NotificationManagerService extends SystemService { } // If we have no Uris to grant, but an existing owner, go destroy it - if (newUris == null && permissionOwner != null) { + // When revoking permissions of a single listener, destroying the owner will revoke + // permissions of other listeners who need to keep access. + if (newUris == null && permissionOwner != null && !onlyRevokeCurrentTarget) { destroyPermissionOwner(permissionOwner, UserHandle.getUserId(oldRecord.getUid()), key); permissionOwner = null; } @@ -7808,9 +7818,20 @@ public class NotificationManagerService extends SystemService { final Uri uri = oldUris.valueAt(i); if (newUris == null || !newUris.contains(uri)) { if (DBG) Slog.d(TAG, key + ": revoking " + uri); - int userId = ContentProvider.getUserIdFromUri( - uri, UserHandle.getUserId(oldRecord.getUid())); - revokeUriPermission(permissionOwner, uri, userId); + if (onlyRevokeCurrentTarget) { + // We're revoking permission from one listener only; other listeners may + // still need access because the notification may still exist + revokeUriPermission(permissionOwner, uri, + UserHandle.getUserId(oldRecord.getUid()), targetPkg, targetUserId); + } else { + // This is broad to unilaterally revoke permissions to this Uri as granted + // by this notification. But this code-path can only be used when the + // reason for revoking is that the notification posted again without this + // Uri, not when removing an individual listener. + revokeUriPermission(permissionOwner, uri, + UserHandle.getUserId(oldRecord.getUid()), + null, UserHandle.USER_ALL); + } } } } @@ -7839,8 +7860,10 @@ public class NotificationManagerService extends SystemService { } } - private void revokeUriPermission(IBinder owner, Uri uri, int userId) { + private void revokeUriPermission(IBinder owner, Uri uri, int sourceUserId, String targetPkg, + int targetUserId) { if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return; + int userId = ContentProvider.getUserIdFromUri(uri, sourceUserId); final long ident = Binder.clearCallingIdentity(); try { @@ -7848,7 +7871,7 @@ public class NotificationManagerService extends SystemService { owner, ContentProvider.getUriWithoutUserId(uri), Intent.FLAG_GRANT_READ_URI_PERMISSION, - userId); + userId, targetPkg, targetUserId); } finally { Binder.restoreCallingIdentity(ident); } @@ -9158,6 +9181,17 @@ public class NotificationManagerService extends SystemService { } @Override + protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId, + boolean isPrimary, boolean enabled) { + super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled); + + getContext().sendBroadcastAsUser( + new Intent(ACTION_NOTIFICATION_LISTENER_ENABLED_CHANGED) + .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), + UserHandle.ALL, null); + } + + @Override protected void loadDefaultsFromConfig() { String defaultListenerAccess = mContext.getResources().getString( R.string.config_defaultListenerAccessPackages); @@ -9219,6 +9253,7 @@ public class NotificationManagerService extends SystemService { final NotificationRankingUpdate update; synchronized (mNotificationLock) { update = makeRankingUpdateLocked(info); + updateUriPermissionsForActiveNotificationsLocked(info, true); } try { listener.onListenerConnected(update); @@ -9230,6 +9265,7 @@ public class NotificationManagerService extends SystemService { @Override @GuardedBy("mNotificationLock") protected void onServiceRemovedLocked(ManagedServiceInfo removed) { + updateUriPermissionsForActiveNotificationsLocked(removed, false); if (removeDisabledHints(removed)) { updateListenerHintsLocked(); updateEffectsSuppressorLocked(); @@ -9296,8 +9332,7 @@ public class NotificationManagerService extends SystemService { for (final ManagedServiceInfo info : getServices()) { boolean sbnVisible = isVisibleToListener(sbn, info); - boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) - : false; + boolean oldSbnVisible = (oldSbn != null) && isVisibleToListener(oldSbn, info); // This notification hasn't been and still isn't visible -> ignore. if (!oldSbnVisible && !sbnVisible) { continue; @@ -9321,13 +9356,8 @@ public class NotificationManagerService extends SystemService { // This notification became invisible -> remove the old one. if (oldSbnVisible && !sbnVisible) { final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight(); - mHandler.post(new Runnable() { - @Override - public void run() { - notifyRemoved( - info, oldSbnLightClone, update, null, REASON_USER_STOPPED); - } - }); + mHandler.post(() -> notifyRemoved( + info, oldSbnLightClone, update, null, REASON_USER_STOPPED)); continue; } @@ -9337,12 +9367,7 @@ public class NotificationManagerService extends SystemService { updateUriPermissions(r, old, info.component.getPackageName(), targetUserId); final StatusBarNotification sbnToPost = trimCache.ForListener(info); - mHandler.post(new Runnable() { - @Override - public void run() { - notifyPosted(info, sbnToPost, update); - } - }); + mHandler.post(() -> notifyPosted(info, sbnToPost, update)); } } catch (Exception e) { Slog.e(TAG, "Could not notify listeners for " + r.getKey(), e); @@ -9350,6 +9375,46 @@ public class NotificationManagerService extends SystemService { } /** + * Synchronously grant or revoke permissions to Uris for all active and visible + * notifications to just the NotificationListenerService provided. + */ + @GuardedBy("mNotificationLock") + private void updateUriPermissionsForActiveNotificationsLocked( + ManagedServiceInfo info, boolean grant) { + try { + for (final NotificationRecord r : mNotificationList) { + // When granting permissions, ignore notifications which are invisible. + // When revoking permissions, all notifications are invisible, so process all. + if (grant && !isVisibleToListener(r.getSbn(), info)) { + continue; + } + // If the notification is hidden, permissions are not required by the listener. + if (r.isHidden() && info.targetSdkVersion < Build.VERSION_CODES.P) { + continue; + } + // Grant or revoke access synchronously + final int targetUserId = (info.userid == UserHandle.USER_ALL) + ? UserHandle.USER_SYSTEM : info.userid; + if (grant) { + // Grant permissions by passing arguments as if the notification is new. + updateUriPermissions(/* newRecord */ r, /* oldRecord */ null, + info.component.getPackageName(), targetUserId); + } else { + // Revoke permissions by passing arguments as if the notification was + // removed, but set `onlyRevokeCurrentTarget` to avoid revoking permissions + // granted to *other* targets by this notification's URIs. + updateUriPermissions(/* newRecord */ null, /* oldRecord */ r, + info.component.getPackageName(), targetUserId, + /* onlyRevokeCurrentTarget */ true); + } + } + } catch (Exception e) { + Slog.e(TAG, "Could not " + (grant ? "grant" : "revoke") + " Uri permissions to " + + info.component, e); + } + } + + /** * asynchronously notify all listeners about a removed notification */ @GuardedBy("mNotificationLock") @@ -9384,18 +9449,11 @@ public class NotificationManagerService extends SystemService { final NotificationStats stats = mAssistants.isServiceTokenValidLocked(info.service) ? notificationStats : null; final NotificationRankingUpdate update = makeRankingUpdateLocked(info); - mHandler.post(new Runnable() { - @Override - public void run() { - notifyRemoved(info, sbnLight, update, stats, reason); - } - }); + mHandler.post(() -> notifyRemoved(info, sbnLight, update, stats, reason)); } // Revoke access after all listeners have been updated - mHandler.post(() -> { - updateUriPermissions(null, r, null, UserHandle.USER_SYSTEM); - }); + mHandler.post(() -> updateUriPermissions(null, r, null, UserHandle.USER_SYSTEM)); } /** diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 840645edcb82..8af74631fb2e 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -613,6 +613,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements throw new IllegalArgumentException( "APEX files can only be installed as part of a staged session."); } + if (params.isMultiPackage) { + throw new IllegalArgumentException("A multi-session can't be set as APEX."); + } } if (params.isStaged && !isCalledBySystemOrShell(callingUid)) { diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index ff9edd511e84..bc090f0aadda 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -1328,12 +1328,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { if (PackageInstaller.STATUS_SUCCESS == status) { mChildSessionsRemaining.removeAt(sessionIndex); if (mChildSessionsRemaining.size() == 0) { - try { - intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, - PackageInstallerSession.this.sessionId); - mStatusReceiver.sendIntent(mContext, 0, intent, null, null); - } catch (IntentSender.SendIntentException ignore) { - } + destroyInternal(); + dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, + "Session installed", null); } } else if (PackageInstaller.STATUS_PENDING_USER_ACTION == status) { try { @@ -1492,53 +1489,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } /** - * Assert multipackage install has consistent sessions. - * - * @throws PackageManagerException if child sessions don't match parent session - * in respect to staged and enable rollback parameters. - */ - @GuardedBy("mLock") - private void assertMultiPackageConsistencyLocked( - @NonNull List<PackageInstallerSession> childSessions) throws PackageManagerException { - for (PackageInstallerSession childSession : childSessions) { - // It might be that the parent session is loaded before all of it's child sessions are, - // e.g. when reading sessions from XML. Those sessions will be null here, and their - // conformance with the multipackage params will be checked when they're loaded. - if (childSession == null) { - continue; - } - assertConsistencyWithLocked(childSession); - } - } - - /** - * Assert consistency with the given session. - * - * @throws PackageManagerException if other sessions doesn't match this session - * in respect to staged and enable rollback parameters. - */ - @GuardedBy("mLock") - private void assertConsistencyWithLocked(PackageInstallerSession other) - throws PackageManagerException { - // Session groups must be consistent wrt to isStaged parameter. Non-staging session - // cannot be grouped with staging sessions. - if (this.params.isStaged != other.params.isStaged) { - throw new PackageManagerException( - PackageManager.INSTALL_FAILED_MULTIPACKAGE_INCONSISTENCY, - "Multipackage Inconsistency: session " + other.sessionId - + " and session " + sessionId - + " have inconsistent staged settings"); - } - if (this.params.getEnableRollback() != other.params.getEnableRollback()) { - throw new PackageManagerException( - PackageManager.INSTALL_FAILED_MULTIPACKAGE_INCONSISTENCY, - "Multipackage Inconsistency: session " + other.sessionId - + " and session " + sessionId - + " have inconsistent rollback settings"); - } - } - - /** * Seal the session to prevent further modification. * * <p>The session will be sealed after calling this method even if it failed. @@ -1552,14 +1502,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { try { assertNoWriteFileTransfersOpenLocked(); assertPreparedAndNotDestroyedLocked("sealing of session"); - mSealed = true; - List<PackageInstallerSession> childSessions = getChildSessionsLocked(); - if (childSessions != null) { - assertMultiPackageConsistencyLocked(childSessions); - } - } catch (PackageManagerException e) { - throw onSessionValidationFailure(e); } catch (Throwable e) { // Convert all exceptions into package manager exceptions as only those are handled // in the code above. @@ -1637,7 +1580,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { * If session should be sealed, then it's sealed to prevent further modification. * If the session can't be sealed then it's destroyed. * - * Additionally for staged APEX sessions read+validate the package and populate req'd fields. + * Additionally for staged APEX/APK sessions read+validate the package and populate req'd + * fields. * * <p> This is meant to be called after all of the sessions are loaded and added to * PackageInstallerService @@ -1670,6 +1614,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // APEX installations rely on certain fields to be populated after reboot. // E.g. mPackageName. validateApexInstallLocked(); + } else { + // Populate mPackageName for this APK session which is required by the staging + // manager to check duplicate apk-in-apex. + PackageInstallerSession parent = allSessions.get(mParentSessionId); + if (parent != null && parent.isStagedSessionReady()) { + validateApkInstallLocked(); + } } } catch (PackageManagerException e) { Slog.e(TAG, "Package not valid", e); @@ -3185,6 +3136,16 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { throw new IllegalStateException("Multi-session " + childSessionId + " can't be a child."); } + if (params.isStaged != childSession.params.isStaged) { + throw new IllegalStateException("Multipackage Inconsistency: session " + + childSession.sessionId + " and session " + sessionId + + " have inconsistent staged settings"); + } + if (params.getEnableRollback() != childSession.params.getEnableRollback()) { + throw new IllegalStateException("Multipackage Inconsistency: session " + + childSession.sessionId + " and session " + sessionId + + " have inconsistent rollback settings"); + } try { acquireTransactionLock(); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 0d1c00dfe035..b96aaf4abd08 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -17591,9 +17591,6 @@ public class PackageManagerService extends IPackageManager.Stub synchronized (mLock) { pkgSetting = mSettings.getPackageLPr(pkgName); } - String abiOverride = - (pkgSetting == null || TextUtils.isEmpty(pkgSetting.cpuAbiOverrideString) - ? args.abiOverride : pkgSetting.cpuAbiOverrideString); boolean isUpdatedSystemAppFromExistingSetting = pkgSetting != null && pkgSetting.getPkgState().isUpdatedSystemApp(); AndroidPackage oldPackage = mPackages.get(pkgName); @@ -17601,7 +17598,7 @@ public class PackageManagerService extends IPackageManager.Stub final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths> derivedAbi = mInjector.getAbiHelper().derivePackageAbi(parsedPackage, isUpdatedSystemAppFromExistingSetting || isUpdatedSystemAppInferred, - abiOverride); + args.abiOverride); derivedAbi.first.applyTo(parsedPackage); derivedAbi.second.applyTo(parsedPackage); } catch (PackageManagerException pme) { diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 3e3e3c590491..3e253673ad31 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -4647,6 +4647,9 @@ public final class Settings { pw.print(prefix); pw.print(" resourcePath="); pw.println(ps.getCodePathString()); pw.print(prefix); pw.print(" legacyNativeLibraryDir="); pw.println(ps.legacyNativeLibraryPathString); + pw.print(prefix); pw.print(" extractNativeLibs="); + pw.println((ps.pkgFlags & ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS) != 0 + ? "true" : "false"); pw.print(prefix); pw.print(" primaryCpuAbi="); pw.println(ps.primaryCpuAbiString); pw.print(prefix); pw.print(" secondaryCpuAbi="); pw.println(ps.secondaryCpuAbiString); } diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index f9bf54a11df0..ac05aabf998f 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -56,6 +56,7 @@ import android.os.UserManagerInternal; import android.os.storage.IStorageManager; import android.os.storage.StorageManager; import android.text.TextUtils; +import android.util.ArraySet; import android.util.IntArray; import android.util.Slog; import android.util.SparseArray; @@ -84,6 +85,7 @@ import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.Set; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; @@ -650,6 +652,7 @@ public class StagingManager { try { if (hasApex) { checkInstallationOfApkInApexSuccessful(session); + checkDuplicateApkInApex(session); snapshotAndRestoreForApexSession(session); Slog.i(TAG, "APEX packages in session " + session.sessionId + " were successfully activated. Proceeding with APK packages, if any"); @@ -829,6 +832,40 @@ public class StagingManager { return null; } + /** + * Throws a PackageManagerException if there are duplicate packages in apk and apk-in-apex. + */ + private void checkDuplicateApkInApex(@NonNull PackageInstallerSession session) + throws PackageManagerException { + if (!session.isMultiPackage()) { + return; + } + final int[] childSessionIds = session.getChildSessionIds(); + final Set<String> apkNames = new ArraySet<>(); + synchronized (mStagedSessions) { + for (int id : childSessionIds) { + final PackageInstallerSession s = mStagedSessions.get(id); + if (!isApexSession(s)) { + apkNames.add(s.getPackageName()); + } + } + } + final List<PackageInstallerSession> apexSessions = extractApexSessions(session); + for (PackageInstallerSession apexSession : apexSessions) { + String packageName = apexSession.getPackageName(); + for (String apkInApex : mApexManager.getApksInApex(packageName)) { + if (!apkNames.add(apkInApex)) { + throw new PackageManagerException( + SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, + "Package: " + packageName + " in session: " + + apexSession.sessionId + " has duplicate apk-in-apex: " + + apkInApex, null); + + } + } + } + } + private void installApksInSession(@NonNull PackageInstallerSession session) throws PackageManagerException { diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index f66b4ee5a1a7..d137fd05f793 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -499,20 +499,23 @@ public class UserManagerService extends IUserManager.Stub { states = new SparseIntArray(); invalidateIsUserUnlockedCache(); } - public int get(int userId) { + public int get(@UserIdInt int userId) { return states.get(userId); } - public int get(int userId, int fallback) { + public int get(@UserIdInt int userId, int fallback) { return states.indexOfKey(userId) >= 0 ? states.get(userId) : fallback; } - public void put(int userId, int state) { + public void put(@UserIdInt int userId, int state) { states.put(userId, state); invalidateIsUserUnlockedCache(); } - public void delete(int userId) { + public void delete(@UserIdInt int userId) { states.delete(userId); invalidateIsUserUnlockedCache(); } + public boolean has(@UserIdInt int userId) { + return states.get(userId, UserHandle.USER_NULL) != UserHandle.USER_NULL; + } @Override public String toString() { return states.toString(); @@ -3561,6 +3564,13 @@ public class UserManagerService extends IUserManager.Stub { if (preCreatedUserData == null) { return null; } + synchronized (mUserStates) { + if (mUserStates.has(preCreatedUserData.info.id)) { + Slog.w(LOG_TAG, "Cannot reuse pre-created user " + + preCreatedUserData.info.id + " because it didn't stop yet"); + return null; + } + } final UserInfo preCreatedUser = preCreatedUserData.info; final int newFlags = preCreatedUser.flags | flags; if (!checkUserTypeConsistency(newFlags)) { @@ -5225,6 +5235,7 @@ public class UserManagerService extends IUserManager.Stub { return userData == null ? null : userData.info; } + @Override public @NonNull UserInfo[] getUserInfos() { synchronized (mUsersLock) { int userSize = mUsers.size(); diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 63aa80e8269a..3d1570476b48 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -881,7 +881,7 @@ public class PermissionManagerService extends IPermissionManager.Stub { } @Override - public int checkPermission(String permName, String pkgName, int userId) { + public int checkPermission(String permName, String pkgName, @UserIdInt int userId) { // Not using Objects.requireNonNull() here for compatibility reasons. if (permName == null || pkgName == null) { return PackageManager.PERMISSION_DENIED; diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java index 4d48a2e63b30..ae2b040d0a89 100644 --- a/services/core/java/com/android/server/policy/PermissionPolicyService.java +++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java @@ -89,7 +89,7 @@ import java.util.concurrent.ExecutionException; public final class PermissionPolicyService extends SystemService { private static final String LOG_TAG = PermissionPolicyService.class.getSimpleName(); private static final boolean DEBUG = false; - private static final long USER_SENSITIVE_UPDATE_DELAY_MS = 10000; + private static final long USER_SENSITIVE_UPDATE_DELAY_MS = 60000; private final Object mLock = new Object(); @@ -283,6 +283,11 @@ public final class PermissionPolicyService extends SystemService { manager.updateUserSensitiveForApp(uid); } }, UserHandle.ALL, intentFilter, null, null); + + PermissionControllerManager manager = new PermissionControllerManager( + getUserContext(getContext(), Process.myUserHandle()), FgThread.getHandler()); + FgThread.getHandler().postDelayed(manager::updateUserSensitive, + USER_SENSITIVE_UPDATE_DELAY_MS); } /** @@ -425,8 +430,7 @@ public final class PermissionPolicyService extends SystemService { throw new IllegalStateException(e); } - FgThread.getHandler().postDelayed(permissionControllerManager::updateUserSensitive, - USER_SENSITIVE_UPDATE_DELAY_MS); + permissionControllerManager.updateUserSensitive(); packageManagerInternal.updateRuntimePermissionsFingerprint(userId); } diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java index ef4954aa4e4c..ae0db4419080 100644 --- a/services/core/java/com/android/server/power/ThermalManagerService.java +++ b/services/core/java/com/android/server/power/ThermalManagerService.java @@ -200,7 +200,7 @@ public class ThermalManagerService extends SystemService { final int count = mTemperatureMap.size(); for (int i = 0; i < count; i++) { Temperature t = mTemperatureMap.valueAt(i); - if (t.getStatus() >= newStatus) { + if (t.getType() == Temperature.TYPE_SKIN && t.getStatus() >= newStatus) { newStatus = t.getStatus(); } } diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java index b3ec849e6c90..8ccbbdd2265c 100755 --- a/services/core/java/com/android/server/tv/TvInputManagerService.java +++ b/services/core/java/com/android/server/tv/TvInputManagerService.java @@ -99,6 +99,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -1177,7 +1178,8 @@ public final class TvInputManagerService extends SystemService { final int resolvedUserId = resolveCallingUserId(callingPid, callingUid, userId, "createSession"); final long identity = Binder.clearCallingIdentity(); - StringBuilder sessionId = new StringBuilder(); + // Generate a unique session id with a random UUID. + String uniqueSessionId = UUID.randomUUID().toString(); try { synchronized (mLock) { if (userId != mCurrentUserId && !isRecordingSession) { @@ -1206,20 +1208,17 @@ public final class TvInputManagerService extends SystemService { return; } - // Create a unique session id with pid, uid and resolved user id - sessionId.append(callingUid).append(callingPid).append(resolvedUserId); - // Create a new session token and a session state. IBinder sessionToken = new Binder(); SessionState sessionState = new SessionState(sessionToken, info.getId(), info.getComponent(), isRecordingSession, client, seq, callingUid, - callingPid, resolvedUserId, sessionId.toString()); + callingPid, resolvedUserId, uniqueSessionId); // Add them to the global session state map of the current user. userState.sessionStateMap.put(sessionToken, sessionState); // Map the session id to the sessionStateMap in the user state - mSessionIdToSessionStateMap.put(sessionId.toString(), sessionState); + mSessionIdToSessionStateMap.put(uniqueSessionId, sessionState); // Also, add them to the session state map of the current service. serviceState.sessionTokens.add(sessionToken); diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java b/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java index 2b0fe8a2602b..2fc17fe65775 100644 --- a/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java +++ b/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java @@ -68,6 +68,11 @@ public final class ClientProfile { private Set<Integer> mUsingFrontendIds = new HashSet<>(); /** + * List of the client ids that share frontend with the current client. + */ + private Set<Integer> mShareFeClientIds = new HashSet<>(); + + /** * List of the Lnb ids that are used by the current client. */ private Set<Integer> mUsingLnbIds = new HashSet<>(); @@ -113,11 +118,7 @@ public final class ClientProfile { } public int getPriority() { - return mPriority; - } - - public int getNiceValue() { - return mNiceValue; + return mPriority - mNiceValue; } public void setGroupId(int groupId) { @@ -141,17 +142,38 @@ public final class ClientProfile { mUsingFrontendIds.add(frontendId); } + /** + * Update the set of client that share frontend with the current client. + * + * @param clientId the client to share the fe with the current client. + */ + public void shareFrontend(int clientId) { + mShareFeClientIds.add(clientId); + } + + /** + * Remove the given client id from the share frontend client id set. + * + * @param clientId the client to stop sharing the fe with the current client. + */ + public void stopSharingFrontend(int clientId) { + mShareFeClientIds.remove(clientId); + } + public Set<Integer> getInUseFrontendIds() { return mUsingFrontendIds; } + public Set<Integer> getShareFeClientIds() { + return mShareFeClientIds; + } + /** * Called when the client released a frontend. - * - * @param frontendId being released. */ - public void releaseFrontend(int frontendId) { - mUsingFrontendIds.remove(frontendId); + public void releaseFrontend() { + mUsingFrontendIds.clear(); + mShareFeClientIds.clear(); } /** @@ -201,6 +223,7 @@ public final class ClientProfile { */ public void reclaimAllResources() { mUsingFrontendIds.clear(); + mShareFeClientIds.clear(); mUsingLnbIds.clear(); mUsingCasSystemId = INVALID_RESOURCE_ID; } diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java index 7cb59dcbfb9b..fb2347e8e133 100644 --- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java +++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java @@ -210,19 +210,36 @@ public class TunerResourceManagerService extends SystemService implements IBinde } synchronized (mLock) { if (!checkClientExists(request.getClientId())) { - throw new RemoteException("Request frontend from unregistered client:" + throw new RemoteException("Request frontend from unregistered client: " + request.getClientId()); } + // If the request client is holding or sharing a frontend, throw an exception. + if (!getClientProfile(request.getClientId()).getInUseFrontendIds().isEmpty()) { + throw new RemoteException("Release frontend before requesting another one. " + + "Client id: " + request.getClientId()); + } return requestFrontendInternal(request, frontendHandle); } } @Override - public void shareFrontend(int selfClientId, int targetClientId) { + public void shareFrontend(int selfClientId, int targetClientId) throws RemoteException { enforceTunerAccessPermission("shareFrontend"); enforceTrmAccessPermission("shareFrontend"); - if (DEBUG) { - Slog.d(TAG, "shareFrontend from " + selfClientId + " with " + targetClientId); + synchronized (mLock) { + if (!checkClientExists(selfClientId)) { + throw new RemoteException("Share frontend request from an unregistered client:" + + selfClientId); + } + if (!checkClientExists(targetClientId)) { + throw new RemoteException("Request to share frontend with an unregistered " + + "client:" + targetClientId); + } + if (getClientProfile(targetClientId).getInUseFrontendIds().isEmpty()) { + throw new RemoteException("Request to share frontend with a client that has no " + + "frontend resources. Target client id:" + targetClientId); + } + shareFrontendInternal(selfClientId, targetClientId); } } @@ -315,7 +332,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde throw new RemoteException( "Client is not the current owner of the releasing fe."); } - releaseFrontendInternal(fe); + releaseFrontendInternal(fe, clientId); } } @@ -649,6 +666,17 @@ public class TunerResourceManagerService extends SystemService implements IBinde } @VisibleForTesting + protected void shareFrontendInternal(int selfClientId, int targetClientId) { + if (DEBUG) { + Slog.d(TAG, "shareFrontend from " + selfClientId + " with " + targetClientId); + } + for (int feId : getClientProfile(targetClientId).getInUseFrontendIds()) { + getClientProfile(selfClientId).useFrontend(feId); + } + getClientProfile(targetClientId).shareFrontend(selfClientId); + } + + @VisibleForTesting protected boolean requestLnbInternal(TunerLnbRequest request, int[] lnbHandle) { if (DEBUG) { Slog.d(TAG, "requestLnb(request=" + request + ")"); @@ -777,11 +805,17 @@ public class TunerResourceManagerService extends SystemService implements IBinde } @VisibleForTesting - protected void releaseFrontendInternal(FrontendResource fe) { + protected void releaseFrontendInternal(FrontendResource fe, int clientId) { if (DEBUG) { - Slog.d(TAG, "releaseFrontend(id=" + fe.getId() + ")"); + Slog.d(TAG, "releaseFrontend(id=" + fe.getId() + ", clientId=" + clientId + " )"); + } + if (clientId == fe.getOwnerClientId()) { + ClientProfile ownerClient = getClientProfile(fe.getOwnerClientId()); + for (int shareOwnerId : ownerClient.getShareFeClientIds()) { + clearFrontendAndClientMapping(getClientProfile(shareOwnerId)); + } } - updateFrontendClientMappingOnRelease(fe); + clearFrontendAndClientMapping(getClientProfile(clientId)); } @VisibleForTesting @@ -882,8 +916,21 @@ public class TunerResourceManagerService extends SystemService implements IBinde Slog.e(TAG, "Failed to reclaim resources on client " + reclaimingClientId, e); return false; } + + // Reclaim all the resources of the share owners of the frontend that is used by the current + // resource reclaimed client. ClientProfile profile = getClientProfile(reclaimingClientId); - reclaimingResourcesFromClient(profile); + Set<Integer> shareFeClientIds = profile.getShareFeClientIds(); + for (int clientId : shareFeClientIds) { + try { + mListeners.get(clientId).getListener().onReclaimResources(); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to reclaim resources on client " + clientId, e); + return false; + } + clearAllResourcesAndClientMapping(getClientProfile(clientId)); + } + clearAllResourcesAndClientMapping(profile); return true; } @@ -929,16 +976,6 @@ public class TunerResourceManagerService extends SystemService implements IBinde } } - private void updateFrontendClientMappingOnRelease(@NonNull FrontendResource releasingFrontend) { - ClientProfile ownerProfile = getClientProfile(releasingFrontend.getOwnerClientId()); - releasingFrontend.removeOwner(); - ownerProfile.releaseFrontend(releasingFrontend.getId()); - for (int exclusiveGroupMember : releasingFrontend.getExclusiveGroupMemberFeIds()) { - getFrontendResource(exclusiveGroupMember).removeOwner(); - ownerProfile.releaseFrontend(exclusiveGroupMember); - } - } - private void updateLnbClientMappingOnNewGrant(int grantingId, int ownerClientId) { LnbResource grantingLnb = getLnbResource(grantingId); ClientProfile ownerProfile = getClientProfile(ownerClientId); @@ -967,10 +1004,10 @@ public class TunerResourceManagerService extends SystemService implements IBinde } /** - * Get the owner client's priority from the resource id. + * Get the owner client's priority. * * @param clientId the owner client id. - * @return the priority of the owner client of the resource. + * @return the priority of the owner client. */ private int getOwnerClientPriority(int clientId) { return getClientProfile(clientId).getPriority(); @@ -1011,7 +1048,11 @@ public class TunerResourceManagerService extends SystemService implements IBinde return; } if (fe.isInUse()) { - releaseFrontendInternal(fe); + ClientProfile ownerClient = getClientProfile(fe.getOwnerClientId()); + for (int shareOwnerId : ownerClient.getShareFeClientIds()) { + clearFrontendAndClientMapping(getClientProfile(shareOwnerId)); + } + clearFrontendAndClientMapping(ownerClient); } for (int excGroupmemberFeId : fe.getExclusiveGroupMemberFeIds()) { getFrontendResource(excGroupmemberFeId) @@ -1093,21 +1134,37 @@ public class TunerResourceManagerService extends SystemService implements IBinde } private void removeClientProfile(int clientId) { - reclaimingResourcesFromClient(getClientProfile(clientId)); + for (int shareOwnerId : getClientProfile(clientId).getShareFeClientIds()) { + clearFrontendAndClientMapping(getClientProfile(shareOwnerId)); + } + clearAllResourcesAndClientMapping(getClientProfile(clientId)); mClientProfiles.remove(clientId); mListeners.remove(clientId); } - private void reclaimingResourcesFromClient(ClientProfile profile) { + private void clearFrontendAndClientMapping(ClientProfile profile) { for (Integer feId : profile.getInUseFrontendIds()) { - getFrontendResource(feId).removeOwner(); + FrontendResource fe = getFrontendResource(feId); + if (fe.getOwnerClientId() == profile.getId()) { + fe.removeOwner(); + continue; + } + getClientProfile(fe.getOwnerClientId()).stopSharingFrontend(profile.getId()); } + profile.releaseFrontend(); + } + + private void clearAllResourcesAndClientMapping(ClientProfile profile) { + // Clear Lnb for (Integer lnbId : profile.getInUseLnbIds()) { getLnbResource(lnbId).removeOwner(); } + // Clear Cas if (profile.getInUseCasSystemId() != ClientProfile.INVALID_RESOURCE_ID) { getCasResource(profile.getInUseCasSystemId()).removeOwner(profile.getId()); } + // Clear Frontend + clearFrontendAndClientMapping(profile); profile.reclaimAllResources(); } diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerInternal.java b/services/core/java/com/android/server/uri/UriGrantsManagerInternal.java index cdb61995c336..5772dea287fc 100644 --- a/services/core/java/com/android/server/uri/UriGrantsManagerInternal.java +++ b/services/core/java/com/android/server/uri/UriGrantsManagerInternal.java @@ -75,10 +75,31 @@ public interface UriGrantsManagerInternal { void removeUriPermissionsForPackage( String packageName, int userHandle, boolean persistable, boolean targetOnly); /** - * @param uri This uri must NOT contain an embedded userId. + * Remove any {@link UriPermission} associated with the owner whose values match the given + * filtering parameters. + * + * @param token An opaque owner token as returned by {@link #newUriPermissionOwner(String)}. + * @param uri This uri must NOT contain an embedded userId. {@code null} to apply to all Uris. + * @param mode The modes (as a bitmask) to revoke. * @param userId The userId in which the uri is to be resolved. */ void revokeUriPermissionFromOwner(IBinder token, Uri uri, int mode, int userId); + + /** + * Remove any {@link UriPermission} associated with the owner whose values match the given + * filtering parameters. + * + * @param token An opaque owner token as returned by {@link #newUriPermissionOwner(String)}. + * @param uri This uri must NOT contain an embedded userId. {@code null} to apply to all Uris. + * @param mode The modes (as a bitmask) to revoke. + * @param userId The userId in which the uri is to be resolved. + * @param targetPkg Calling package name to match, or {@code null} to apply to all packages. + * @param targetUserId Calling user to match, or {@link UserHandle#USER_ALL} to apply to all + * users. + */ + void revokeUriPermissionFromOwner(IBinder token, Uri uri, int mode, int userId, + String targetPkg, int targetUserId); + boolean checkAuthorityGrants( int callingUid, ProviderInfo cpi, int userId, boolean checkUser); void dump(PrintWriter pw, boolean dumpAll, String dumpPackage); diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java index f5e1602ee6be..a106dc682208 100644 --- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java +++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java @@ -51,7 +51,6 @@ import android.app.AppGlobals; import android.app.GrantedUriPermission; import android.app.IUriGrantsManager; import android.content.ClipData; -import android.content.ComponentName; import android.content.ContentProvider; import android.content.ContentResolver; import android.content.Context; @@ -88,11 +87,11 @@ import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.SystemServiceManager; -import libcore.io.IoUtils; - import com.google.android.collect.Lists; import com.google.android.collect.Maps; +import libcore.io.IoUtils; + import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; @@ -1431,16 +1430,18 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub { @Override public void revokeUriPermissionFromOwner(IBinder token, Uri uri, int mode, int userId) { + revokeUriPermissionFromOwner(token, uri, mode, userId, null, UserHandle.USER_ALL); + } + + @Override + public void revokeUriPermissionFromOwner(IBinder token, Uri uri, int mode, int userId, + String targetPkg, int targetUserId) { final UriPermissionOwner owner = UriPermissionOwner.fromExternalToken(token); if (owner == null) { throw new IllegalArgumentException("Unknown owner: " + token); } - - if (uri == null) { - owner.removeUriPermissions(mode); - } else { - owner.removeUriPermission(new GrantUri(userId, uri, mode), mode); - } + GrantUri grantUri = uri == null ? null : new GrantUri(userId, uri, mode); + owner.removeUriPermission(grantUri, mode, targetPkg, targetUserId); } @Override diff --git a/services/core/java/com/android/server/uri/UriPermissionOwner.java b/services/core/java/com/android/server/uri/UriPermissionOwner.java index 2b404a43a338..0c263997a8b5 100644 --- a/services/core/java/com/android/server/uri/UriPermissionOwner.java +++ b/services/core/java/com/android/server/uri/UriPermissionOwner.java @@ -21,6 +21,7 @@ import static android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION; import android.os.Binder; import android.os.IBinder; +import android.os.UserHandle; import android.util.ArraySet; import android.util.proto.ProtoOutputStream; @@ -74,30 +75,47 @@ public class UriPermissionOwner { } void removeUriPermission(GrantUri grantUri, int mode) { + removeUriPermission(grantUri, mode, null, UserHandle.USER_ALL); + } + + void removeUriPermission(GrantUri grantUri, int mode, String targetPgk, int targetUserId) { if ((mode & FLAG_GRANT_READ_URI_PERMISSION) != 0 && mReadPerms != null) { Iterator<UriPermission> it = mReadPerms.iterator(); while (it.hasNext()) { UriPermission perm = it.next(); - if (grantUri == null || grantUri.equals(perm.uri)) { - perm.removeReadOwner(this); - mService.removeUriPermissionIfNeeded(perm); - it.remove(); + if (grantUri != null && !grantUri.equals(perm.uri)) { + continue; + } + if (targetPgk != null && !targetPgk.equals(perm.targetPkg)) { + continue; } + if (targetUserId != UserHandle.USER_ALL && targetUserId != perm.targetUserId) { + continue; + } + perm.removeReadOwner(this); + mService.removeUriPermissionIfNeeded(perm); + it.remove(); } if (mReadPerms.isEmpty()) { mReadPerms = null; } } - if ((mode & FLAG_GRANT_WRITE_URI_PERMISSION) != 0 - && mWritePerms != null) { + if ((mode & FLAG_GRANT_WRITE_URI_PERMISSION) != 0 && mWritePerms != null) { Iterator<UriPermission> it = mWritePerms.iterator(); while (it.hasNext()) { UriPermission perm = it.next(); - if (grantUri == null || grantUri.equals(perm.uri)) { - perm.removeWriteOwner(this); - mService.removeUriPermissionIfNeeded(perm); - it.remove(); + if (grantUri != null && !grantUri.equals(perm.uri)) { + continue; + } + if (targetPgk != null && !targetPgk.equals(perm.targetPkg)) { + continue; + } + if (targetUserId != UserHandle.USER_ALL && targetUserId != perm.targetUserId) { + continue; } + perm.removeWriteOwner(this); + mService.removeUriPermissionIfNeeded(perm); + it.remove(); } if (mWritePerms.isEmpty()) { mWritePerms = null; diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 5b8078729eee..e4f28546a5fd 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -2549,7 +2549,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final Task stack = getRootTask(); final boolean mayAdjustTop = (isState(RESUMED) || stack.mResumedActivity == null) - && stack.isFocusedStackOnDisplay(); + && stack.isFocusedStackOnDisplay() + // Do not adjust focus task because the task will be reused to launch new activity. + && !task.isClearingToReuseTask(); final boolean shouldAdjustGlobalFocus = mayAdjustTop // It must be checked before {@link #makeFinishingLocked} is called, because a stack // is not visible if it only contains finishing activities. diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index f7cb0146ea52..15e88fc44746 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -2023,8 +2023,6 @@ class ActivityStarter { // of history or if it is finished immediately), thus disassociating the task. Also note // that mReuseTask is reset as a result of {@link Task#performClearTaskLocked} // launching another activity. - // TODO(b/36119896): We shouldn't trigger activity launches in this path since we are - // already launching one. targetTask.performClearTaskLocked(); targetTask.setIntent(mStartActivity); mAddingToTask = true; diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 31a9c5d4242c..8204b36bc551 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -251,7 +251,6 @@ import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.AttributeCache; import com.android.server.LocalServices; import com.android.server.SystemService; -import com.android.server.SystemService.TargetUser; import com.android.server.SystemServiceManager; import com.android.server.UiThread; import com.android.server.Watchdog; @@ -5347,15 +5346,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return mAmInternal.isBackgroundActivityStartsEnabled(); } - void enableScreenAfterBoot(boolean booted) { - writeBootProgressEnableScreen(SystemClock.uptimeMillis()); - mWindowManager.enableScreenAfterBoot(); - - synchronized (mGlobalLock) { - updateEventDispatchingLocked(booted); - } - } - static long getInputDispatchingTimeoutMillisLocked(ActivityRecord r) { if (r == null || !r.hasProcess()) { return DEFAULT_DISPATCHING_TIMEOUT_MILLIS; @@ -6449,9 +6439,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void enableScreenAfterBoot(boolean booted) { + writeBootProgressEnableScreen(SystemClock.uptimeMillis()); + mWindowManager.enableScreenAfterBoot(); synchronized (mGlobalLock) { - writeBootProgressEnableScreen(SystemClock.uptimeMillis()); - mWindowManager.enableScreenAfterBoot(); updateEventDispatchingLocked(booted); } } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index ba5a38290349..affbafa095cc 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -1557,7 +1557,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // the heavy operations. This also benefits that the states of multiple activities // are handled together. r.linkFixedRotationTransform(prevRotatedLaunchingApp); - setFixedRotationLaunchingAppUnchecked(r, rotation); + if (r != mFixedRotationTransitionListener.mAnimatingRecents) { + // Only update the record for normal activity so the display orientation can be + // updated when the transition is done if it becomes the top. And the case of + // recents can be handled when the recents animation is finished. + setFixedRotationLaunchingAppUnchecked(r, rotation); + } return; } diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java index df5356303f8b..3c64ffb237d6 100644 --- a/services/core/java/com/android/server/wm/RecentTasks.java +++ b/services/core/java/com/android/server/wm/RecentTasks.java @@ -1627,8 +1627,8 @@ class RecentTasks { } if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: adding affilliates starting at " + topIndex + " from intial " + taskIndex); - // Find the end of the chain, doing a sanity check along the way. - boolean sane = top.mAffiliatedTaskId == task.mAffiliatedTaskId; + // Find the end of the chain, doing a validity check along the way. + boolean isValid = top.mAffiliatedTaskId == task.mAffiliatedTaskId; int endIndex = topIndex; Task prev = top; while (endIndex < recentsCount) { @@ -1640,7 +1640,7 @@ class RecentTasks { if (cur.mNextAffiliate != null || cur.mNextAffiliateTaskId != INVALID_TASK_ID) { Slog.wtf(TAG, "Bad chain @" + endIndex + ": first task has next affiliate: " + prev); - sane = false; + isValid = false; break; } } else { @@ -1652,7 +1652,7 @@ class RecentTasks { + " has bad next affiliate " + cur.mNextAffiliate + " id " + cur.mNextAffiliateTaskId + ", expected " + prev); - sane = false; + isValid = false; break; } } @@ -1662,7 +1662,7 @@ class RecentTasks { Slog.wtf(TAG, "Bad chain @" + endIndex + ": last task " + cur + " has previous affiliate " + cur.mPrevAffiliate); - sane = false; + isValid = false; } if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: end of chain @" + endIndex); break; @@ -1673,7 +1673,7 @@ class RecentTasks { + ": task " + cur + " has previous affiliate " + cur.mPrevAffiliate + " but should be id " + cur.mPrevAffiliate); - sane = false; + isValid = false; break; } } @@ -1682,7 +1682,7 @@ class RecentTasks { + ": task " + cur + " has affiliated id " + cur.mAffiliatedTaskId + " but should be " + task.mAffiliatedTaskId); - sane = false; + isValid = false; break; } prev = cur; @@ -1690,18 +1690,18 @@ class RecentTasks { if (endIndex >= recentsCount) { Slog.wtf(TAG, "Bad chain ran off index " + endIndex + ": last task " + prev); - sane = false; + isValid = false; break; } } - if (sane) { + if (isValid) { if (endIndex < taskIndex) { Slog.wtf(TAG, "Bad chain @" + endIndex + ": did not extend to task " + task + " @" + taskIndex); - sane = false; + isValid = false; } } - if (sane) { + if (isValid) { // All looks good, we can just move all of the affiliated tasks // to the top. for (int i=topIndex; i<=endIndex; i++) { diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index b3a3ed7eeba4..fe2d08f6a4c2 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -737,7 +737,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> winAnimator.mSession.mPid, operation); final long callingIdentity = Binder.clearCallingIdentity(); try { - // There was some problem...first, do a sanity check of the window list to make sure + // There was some problem...first, do a validity check of the window list to make sure // we haven't left any dangling surfaces around. Slog.i(TAG_WM, "Out of memory for surface! Looking for leaks..."); @@ -811,7 +811,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } // "Something has changed! Let's make it correct now." - // TODO: Super crazy long method that should be broken down... + // TODO: Super long method that should be broken down... void performSurfacePlacementNoTrace() { if (DEBUG_WINDOW_TRACE) Slog.v(TAG, "performSurfacePlacementInner: entry. Called by " + Debug.getCallers(3)); diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index ec7b1eed7f91..0529abf89f6e 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -1836,14 +1836,25 @@ class Task extends WindowContainer<WindowContainer> { */ void performClearTaskLocked() { mReuseTask = true; - performClearTask("clear-task-all"); - mReuseTask = false; + mStackSupervisor.beginDeferResume(); + try { + performClearTask("clear-task-all"); + } finally { + mStackSupervisor.endDeferResume(); + mReuseTask = false; + } } ActivityRecord performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags) { mReuseTask = true; - final ActivityRecord result = performClearTaskLocked(newR, launchFlags); - mReuseTask = false; + mStackSupervisor.beginDeferResume(); + final ActivityRecord result; + try { + result = performClearTaskLocked(newR, launchFlags); + } finally { + mStackSupervisor.endDeferResume(); + mReuseTask = false; + } return result; } diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index 68445f6970fb..dbbb7ff69b3b 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -27,7 +27,6 @@ import android.annotation.Nullable; import android.app.ActivityManager.TaskSnapshot; import android.content.pm.PackageManager; import android.graphics.Bitmap; -import android.graphics.Insets; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.RecordingCanvas; @@ -82,7 +81,7 @@ class TaskSnapshotController { /** * Return value for {@link #getSnapshotMode}: We are not allowed to take a real screenshot but - * we should try to use the app theme to create a dummy representation of the app. + * we should try to use the app theme to create a fake representation of the app. */ @VisibleForTesting static final int SNAPSHOT_MODE_APP_THEME = 1; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index b33a8e9ef5df..7624d4c1ea36 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -3612,7 +3612,7 @@ public class WindowManagerService extends IWindowManager.Stub } if (SHOW_VERBOSE_TRANSACTIONS) Slog.i(TAG_WM, ">>> showStrictModeViolation"); - // TODO: Modify this to use the surface trace once it is not going crazy. + // TODO: Modify this to use the surface trace once it is not going baffling. // b/31532461 // TODO(multi-display): support multiple displays if (mStrictModeFlash == null) { diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index ab6e35b452a0..c714eeb92e68 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -196,7 +196,6 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio private final Configuration mLastReportedConfiguration = new Configuration(); // Configuration that is waiting to be dispatched to the process. private Configuration mPendingConfiguration; - private final Configuration mNewOverrideConfig = new Configuration(); // Registered display id as a listener to override config change private int mDisplayId; private ActivityRecord mConfigActivityRecord; @@ -1292,11 +1291,26 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio } @Override + public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) { + super.onRequestedOverrideConfigurationChanged( + sanitizeProcessConfiguration(overrideConfiguration)); + } + + @Override public void onMergedOverrideConfigurationChanged(Configuration mergedOverrideConfig) { + super.onRequestedOverrideConfigurationChanged( + sanitizeProcessConfiguration(mergedOverrideConfig)); + } + + private static Configuration sanitizeProcessConfiguration(Configuration config) { // Make sure that we don't accidentally override the activity type. - mNewOverrideConfig.setTo(mergedOverrideConfig); - mNewOverrideConfig.windowConfiguration.setActivityType(ACTIVITY_TYPE_UNDEFINED); - super.onRequestedOverrideConfigurationChanged(mNewOverrideConfig); + if (config.windowConfiguration.getActivityType() != ACTIVITY_TYPE_UNDEFINED) { + final Configuration sanitizedConfig = new Configuration(config); + sanitizedConfig.windowConfiguration.setActivityType(ACTIVITY_TYPE_UNDEFINED); + return sanitizedConfig; + } + + return config; } private void updateConfiguration() { diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index ebbd74aa7d1e..49e623d8dd11 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -2456,9 +2456,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP finishInputEvent(event, true); } } - /** - * Dummy event receiver for windows that died visible. - */ + /** Fake event receiver for windows that died visible. */ private DeadWindowEventReceiver mDeadWindowEventReceiver; void openInputChannel(InputChannel outInputChannel) { @@ -2476,9 +2474,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mClientChannel.dispose(); mClientChannel = null; } else { - // If the window died visible, we setup a dummy input channel, so that taps + // If the window died visible, we setup a fake input channel, so that taps // can still detected by input monitor channel, and we can relaunch the app. - // Create dummy event receiver that simply reports all events as handled. + // Create fake event receiver that simply reports all events as handled. mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel); } mWmService.mInputToWindowMap.put(mInputWindowHandle.token, this); diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 16edb55939a3..92177abbbf85 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -560,9 +560,9 @@ class WindowStateAnimator { } } - // Something is wrong and SurfaceFlinger will not like this, try to revert to sane values. - // This doesn't necessarily mean that there is an error in the system. The sizes might be - // incorrect, because it is before the first layout or draw. + // Something is wrong and SurfaceFlinger will not like this, try to revert to reasonable + // values. This doesn't necessarily mean that there is an error in the system. The sizes + // might be incorrect, because it is before the first layout or draw. if (outSize.width() < 1) { outSize.right = 1; } diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index f7cd37fb6748..bc4d9a973ecb 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -548,7 +548,7 @@ class WindowToken extends WindowContainer<WindowState> { void applyFixedRotationTransform(DisplayInfo info, DisplayFrames displayFrames, Configuration config) { if (mFixedRotationTransformState != null) { - return; + cleanUpFixedRotationTransformState(true /* replacing */); } mFixedRotationTransformState = new FixedRotationTransformState(info, displayFrames, new Configuration(config), mDisplayContent.getRotation()); @@ -565,13 +565,13 @@ class WindowToken extends WindowContainer<WindowState> { * one. This takes the same effect as {@link #applyFixedRotationTransform}. */ void linkFixedRotationTransform(WindowToken other) { - if (mFixedRotationTransformState != null) { - return; - } final FixedRotationTransformState fixedRotationState = other.mFixedRotationTransformState; - if (fixedRotationState == null) { + if (fixedRotationState == null || mFixedRotationTransformState == fixedRotationState) { return; } + if (mFixedRotationTransformState != null) { + cleanUpFixedRotationTransformState(true /* replacing */); + } mFixedRotationTransformState = fixedRotationState; fixedRotationState.mAssociatedTokens.add(this); onConfigurationChanged(getParent().getConfiguration()); @@ -626,11 +626,17 @@ class WindowToken extends WindowContainer<WindowState> { // The state is cleared at the end, because it is used to indicate that other windows can // use seamless rotation when applying rotation to display. for (int i = state.mAssociatedTokens.size() - 1; i >= 0; i--) { - state.mAssociatedTokens.get(i).cleanUpFixedRotationTransformState(); + state.mAssociatedTokens.get(i).cleanUpFixedRotationTransformState( + false /* replacing */); } } - private void cleanUpFixedRotationTransformState() { + private void cleanUpFixedRotationTransformState(boolean replacing) { + if (replacing && mFixedRotationTransformState.mAssociatedTokens.size() > 1) { + // The state is not only used by self. Make sure to leave the influence by others. + mFixedRotationTransformState.mAssociatedTokens.remove(this); + mFixedRotationTransformState.mRotatedContainers.remove(this); + } mFixedRotationTransformState = null; notifyFixedRotationTransform(false /* enabled */); } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/CallerIdentity.java b/services/devicepolicy/java/com/android/server/devicepolicy/CallerIdentity.java new file mode 100644 index 000000000000..5193fa85d238 --- /dev/null +++ b/services/devicepolicy/java/com/android/server/devicepolicy/CallerIdentity.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.devicepolicy; + +import android.annotation.Nullable; +import android.content.ComponentName; +import android.os.UserHandle; + +/** + * Caller identity containing the caller's UID, package name and component name. + * All parameters are verified on object creation unless the component name is null and the + * caller is a delegate. + */ +class CallerIdentity { + + private final int mUid; + @Nullable + private final String mPackageName; + @Nullable + private final ComponentName mComponentName; + + CallerIdentity(int uid, @Nullable String packageName, @Nullable ComponentName componentName) { + mUid = uid; + mPackageName = packageName; + mComponentName = componentName; + } + + public int getUid() { + return mUid; + } + + public int getUserId() { + return UserHandle.getUserId(mUid); + } + + public UserHandle getUserHandle() { + return UserHandle.getUserHandleForUid(mUid); + } + + @Nullable public String getPackageName() { + return mPackageName; + } + + @Nullable public ComponentName getComponentName() { + return mComponentName; + } +} diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index cafd56e5198b..2ab629bf725a 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -1564,6 +1564,39 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } /** + * Creates a new {@link CallerIdentity} object to represent the caller's identity. + */ + private CallerIdentity getCallerIdentity(String callerPackage) { + final int callerUid = mInjector.binderGetCallingUid(); + + if (!isCallingFromPackage(callerPackage, callerUid)) { + throw new SecurityException( + String.format("Caller with uid %d is not %s", callerUid, callerPackage)); + } + + return new CallerIdentity(callerUid, callerPackage, null); + } + + /** + * Creates a new {@link CallerIdentity} object to represent the caller's identity. + */ + private CallerIdentity getCallerIdentity(@NonNull ComponentName componentName) { + final int callerUid = mInjector.binderGetCallingUid(); + final DevicePolicyData policy = getUserData(UserHandle.getUserId(callerUid)); + ActiveAdmin admin = policy.mAdminMap.get(componentName); + + if (admin == null) { + throw new SecurityException(String.format("No active admin for %s", componentName)); + } + if (admin.getUid() != callerUid) { + throw new SecurityException( + String.format("Admin %s is not owned by uid %d", componentName, callerUid)); + } + + return new CallerIdentity(callerUid, componentName.getPackageName(), componentName); + } + + /** * Checks if the device is in COMP mode, and if so migrates it to managed profile on a * corporate owned device. */ @@ -7171,6 +7204,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } + private boolean isDeviceOwner(CallerIdentity identity) { + synchronized (getLockObject()) { + return mOwners.hasDeviceOwner() + && mOwners.getDeviceOwnerUserId() == identity.getUserId() + && mOwners.getDeviceOwnerComponent().equals(identity.getComponentName()); + } + } + private boolean isDeviceOwnerPackage(String packageName, int userId) { synchronized (getLockObject()) { return mOwners.hasDeviceOwner() @@ -10427,20 +10468,20 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @Override public void setLocationEnabled(ComponentName who, boolean locationEnabled) { - enforceDeviceOwner(Objects.requireNonNull(who)); - - UserHandle user = mInjector.binderGetCallingUserHandle(); + CallerIdentity identity = getCallerIdentity(who); + Preconditions.checkCallAuthorization(isDeviceOwner(identity)); mInjector.binderWithCleanCallingIdentity(() -> { boolean wasLocationEnabled = mInjector.getLocationManager().isLocationEnabledForUser( - user); - mInjector.getLocationManager().setLocationEnabledForUser(locationEnabled, user); + identity.getUserHandle()); + mInjector.getLocationManager().setLocationEnabledForUser(locationEnabled, + identity.getUserHandle()); // make a best effort to only show the notification if the admin is actually enabling // location. this is subject to race conditions with settings changes, but those are // unlikely to realistically interfere - if (locationEnabled && (wasLocationEnabled != locationEnabled)) { - showLocationSettingsEnabledNotification(user); + if (locationEnabled && !wasLocationEnabled) { + showLocationSettingsEnabledNotification(identity.getUserHandle()); } }); diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java index 6a797f31fa55..03dce4c62fe8 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityManagerServiceTest.java @@ -32,7 +32,6 @@ import static android.util.DebugUtils.valueToString; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; import static com.android.server.am.ActivityManagerInternalTest.CustomThread; -import static com.android.server.am.ActivityManagerService.DISPATCH_UIDS_CHANGED_UI_MSG; import static com.android.server.am.ActivityManagerService.Injector; import static com.android.server.am.ProcessList.NETWORK_STATE_BLOCK; import static com.android.server.am.ProcessList.NETWORK_STATE_NO_CHANGE; @@ -548,10 +547,10 @@ public class ActivityManagerServiceTest { pendingChange.processState = procStatesForPendingUidRecords[i]; pendingChange.procStateSeq = i; changeItems.put(changesForPendingUidRecords[i], pendingChange); - mAms.mPendingUidChanges.add(pendingChange); + mAms.mUidObserverController.mPendingUidChanges.add(pendingChange); } - mAms.dispatchUidsChanged(); + mAms.mUidObserverController.dispatchUidsChanged(); // Verify the required changes have been dispatched to observers. for (int i = 0; i < observers.length; ++i) { final int changeToObserve = changesToObserve[i]; @@ -647,8 +646,8 @@ public class ActivityManagerServiceTest { changeItem.change = UidRecord.CHANGE_PROCSTATE; changeItem.processState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY; changeItem.procStateSeq = 111; - mAms.mPendingUidChanges.add(changeItem); - mAms.dispatchUidsChanged(); + mAms.mUidObserverController.mPendingUidChanges.add(changeItem); + mAms.mUidObserverController.dispatchUidsChanged(); // First process state message is always delivered regardless of whether the process state // change is above or below the cutpoint (PROCESS_STATE_SERVICE). verify(observer).onUidStateChanged(TEST_UID, @@ -657,15 +656,15 @@ public class ActivityManagerServiceTest { verifyNoMoreInteractions(observer); changeItem.processState = ActivityManager.PROCESS_STATE_RECEIVER; - mAms.mPendingUidChanges.add(changeItem); - mAms.dispatchUidsChanged(); + mAms.mUidObserverController.mPendingUidChanges.add(changeItem); + mAms.mUidObserverController.dispatchUidsChanged(); // Previous process state change is below cutpoint (PROCESS_STATE_SERVICE) and // the current process state change is also below cutpoint, so no callback will be invoked. verifyNoMoreInteractions(observer); changeItem.processState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE; - mAms.mPendingUidChanges.add(changeItem); - mAms.dispatchUidsChanged(); + mAms.mUidObserverController.mPendingUidChanges.add(changeItem); + mAms.mUidObserverController.dispatchUidsChanged(); // Previous process state change is below cutpoint (PROCESS_STATE_SERVICE) and // the current process state change is above cutpoint, so callback will be invoked with the // current process state change. @@ -675,15 +674,15 @@ public class ActivityManagerServiceTest { verifyNoMoreInteractions(observer); changeItem.processState = ActivityManager.PROCESS_STATE_TOP; - mAms.mPendingUidChanges.add(changeItem); - mAms.dispatchUidsChanged(); + mAms.mUidObserverController.mPendingUidChanges.add(changeItem); + mAms.mUidObserverController.dispatchUidsChanged(); // Previous process state change is above cutpoint (PROCESS_STATE_SERVICE) and // the current process state change is also above cutpoint, so no callback will be invoked. verifyNoMoreInteractions(observer); changeItem.processState = ActivityManager.PROCESS_STATE_CACHED_EMPTY; - mAms.mPendingUidChanges.add(changeItem); - mAms.dispatchUidsChanged(); + mAms.mUidObserverController.mPendingUidChanges.add(changeItem); + mAms.mUidObserverController.dispatchUidsChanged(); // Previous process state change is above cutpoint (PROCESS_STATE_SERVICE) and // the current process state change is below cutpoint, so callback will be invoked with the // current process state change. @@ -720,20 +719,21 @@ public class ActivityManagerServiceTest { // Verify that when there no observers listening to uid state changes, then there will // be no changes to validateUids. - mAms.mPendingUidChanges.addAll(pendingItemsForUids); - mAms.dispatchUidsChanged(); + mAms.mUidObserverController.mPendingUidChanges.addAll(pendingItemsForUids); + mAms.mUidObserverController.dispatchUidsChanged(); assertEquals("No observers registered, so validateUids should be empty", - 0, mAms.mValidateUids.size()); + 0, mAms.mUidObserverController.mValidateUids.size()); final IUidObserver observer = mock(IUidObserver.Stub.class); when(observer.asBinder()).thenReturn((IBinder) observer); mAms.registerUidObserver(observer, 0, 0, null); // Verify that when observers are registered, then validateUids is correctly updated. - mAms.mPendingUidChanges.addAll(pendingItemsForUids); - mAms.dispatchUidsChanged(); + mAms.mUidObserverController.mPendingUidChanges.addAll(pendingItemsForUids); + mAms.mUidObserverController.dispatchUidsChanged(); for (int i = 0; i < pendingItemsForUids.size(); ++i) { final UidRecord.ChangeItem item = pendingItemsForUids.get(i); - final UidRecord validateUidRecord = mAms.mValidateUids.get(item.uid); + final UidRecord validateUidRecord = + mAms.mUidObserverController.mValidateUids.get(item.uid); if ((item.change & UidRecord.CHANGE_GONE) != 0) { assertNull("validateUidRecord should be null since the change is either " + "CHANGE_GONE or CHANGE_GONE_IDLE", validateUidRecord); @@ -759,7 +759,7 @@ public class ActivityManagerServiceTest { // Verify that when uid state changes to CHANGE_GONE or CHANGE_GONE_IDLE, then it // will be removed from validateUids. assertNotEquals("validateUids should not be empty", 0, - mAms.mValidateUids.size()); + mAms.mUidObserverController.mValidateUids.size()); for (int i = 0; i < pendingItemsForUids.size(); ++i) { final UidRecord.ChangeItem item = pendingItemsForUids.get(i); // Assign CHANGE_GONE_IDLE to some items and CHANGE_GONE to the others, using even/odd @@ -767,10 +767,11 @@ public class ActivityManagerServiceTest { item.change = (i % 2) == 0 ? (UidRecord.CHANGE_GONE | UidRecord.CHANGE_IDLE) : UidRecord.CHANGE_GONE; } - mAms.mPendingUidChanges.addAll(pendingItemsForUids); - mAms.dispatchUidsChanged(); - assertEquals("validateUids should be empty, size=" + mAms.mValidateUids.size(), - 0, mAms.mValidateUids.size()); + mAms.mUidObserverController.mPendingUidChanges.addAll(pendingItemsForUids); + mAms.mUidObserverController.dispatchUidsChanged(); + assertEquals("validateUids should be empty, size=" + + mAms.mUidObserverController.mValidateUids.size(), + 0, mAms.mUidObserverController.mValidateUids.size()); } @Test @@ -792,7 +793,7 @@ public class ActivityManagerServiceTest { @Test public void testEnqueueUidChangeLocked_nullUidRecord() { // Use "null" uidRecord to make sure there is no crash. - mAms.enqueueUidChangeLocked(null, TEST_UID, UidRecord.CHANGE_ACTIVE); + mAms.mUidObserverController.enqueueUidChangeLocked(null, TEST_UID, UidRecord.CHANGE_ACTIVE); } private void verifyLastProcStateSeqUpdated(UidRecord uidRecord, int uid, long curProcstateSeq) { @@ -801,7 +802,7 @@ public class ActivityManagerServiceTest { final int changeToDispatch = UID_RECORD_CHANGES[i]; // Reset lastProcStateSeqDispatchToObservers after every test. uidRecord.lastDispatchedProcStateSeq = 0; - mAms.enqueueUidChangeLocked(uidRecord, uid, changeToDispatch); + mAms.mUidObserverController.enqueueUidChangeLocked(uidRecord, uid, changeToDispatch); // Verify there is no effect on curProcStateSeq. assertEquals(curProcstateSeq, uidRecord.curProcStateSeq); if ((changeToDispatch & UidRecord.CHANGE_GONE) != 0) { @@ -833,9 +834,9 @@ public class ActivityManagerServiceTest { // Reset the current state mHandler.reset(); uidRecord.pendingChange = null; - mAms.mPendingUidChanges.clear(); + mAms.mUidObserverController.mPendingUidChanges.clear(); - mAms.enqueueUidChangeLocked(uidRecord, -1, changeToDispatch); + mAms.mUidObserverController.enqueueUidChangeLocked(uidRecord, -1, changeToDispatch); // Verify that UidRecord.pendingChange is updated correctly. assertNotNull(uidRecord.pendingChange); @@ -843,8 +844,7 @@ public class ActivityManagerServiceTest { assertEquals(expectedProcState, uidRecord.pendingChange.processState); assertEquals(TEST_PROC_STATE_SEQ1, uidRecord.pendingChange.procStateSeq); - // Verify that DISPATCH_UIDS_CHANGED_UI_MSG is posted to handler. - mHandler.waitForMessage(DISPATCH_UIDS_CHANGED_UI_MSG); + // TODO: Verify that DISPATCH_UIDS_CHANGED_UI_MSG is posted to handler. } } diff --git a/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java b/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java index a9cef20268f4..609af8d5bf4d 100644 --- a/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java +++ b/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java @@ -21,6 +21,8 @@ import android.media.AudioDeviceAttributes; import android.media.AudioSystem; import android.util.Log; +import java.util.List; + /** * Provides an adapter for AudioSystem that does nothing. * Overridden methods can be configured. @@ -66,13 +68,13 @@ public class NoOpAudioSystemAdapter extends AudioSystemAdapter { } @Override - public int setPreferredDeviceForStrategy(int strategy, - @NonNull AudioDeviceAttributes device) { + public int setDevicesRoleForStrategy(int strategy, int role, + @NonNull List<AudioDeviceAttributes> devices) { return AudioSystem.AUDIO_STATUS_OK; } @Override - public int removePreferredDeviceForStrategy(int strategy) { + public int removeDevicesRoleForStrategy(int strategy, int role) { return AudioSystem.AUDIO_STATUS_OK; } diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java index dad360d40515..36c55cce076b 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java @@ -17,7 +17,6 @@ package com.android.server.biometrics.sensors; import android.content.Context; -import android.os.IBinder; import android.platform.test.annotations.Presubmit; import androidx.annotation.NonNull; @@ -56,8 +55,8 @@ public class BiometricSchedulerTest { mScheduler.scheduleClientMonitor(client1); mScheduler.scheduleClientMonitor(client2); - client1.mFinishCallback.onClientFinished(client1, true /* success */); - client1.mFinishCallback.onClientFinished(client1, true /* success */); + client1.mCallback.onClientFinished(client1, true /* success */); + client1.mCallback.onClientFinished(client1, true /* success */); } private static class TestClientMonitor extends ClientMonitor<Object> { diff --git a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java index e4c9cc3c05d9..1d914ec083fa 100644 --- a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java @@ -88,36 +88,36 @@ public class InputMethodUtilsTest { public void testVoiceImes() throws Exception { // locale: en_US assertDefaultEnabledImes(getImesWithDefaultVoiceIme(), LOCALE_EN_US, - "DummyDefaultEnKeyboardIme", "DummyDefaultAutoVoiceIme"); + "FakeDefaultEnKeyboardIme", "FakeDefaultAutoVoiceIme"); assertDefaultEnabledImes(getImesWithoutDefaultVoiceIme(), LOCALE_EN_US, - "DummyDefaultEnKeyboardIme", "DummyNonDefaultAutoVoiceIme0", - "DummyNonDefaultAutoVoiceIme1"); + "FakeDefaultEnKeyboardIme", "FakeNonDefaultAutoVoiceIme0", + "FakeNonDefaultAutoVoiceIme1"); assertDefaultEnabledMinimumImes(getImesWithDefaultVoiceIme(), LOCALE_EN_US, - "DummyDefaultEnKeyboardIme"); + "FakeDefaultEnKeyboardIme"); assertDefaultEnabledMinimumImes(getImesWithoutDefaultVoiceIme(), LOCALE_EN_US, - "DummyDefaultEnKeyboardIme"); + "FakeDefaultEnKeyboardIme"); // locale: en_GB assertDefaultEnabledImes(getImesWithDefaultVoiceIme(), LOCALE_EN_GB, - "DummyDefaultEnKeyboardIme", "DummyDefaultAutoVoiceIme"); + "FakeDefaultEnKeyboardIme", "FakeDefaultAutoVoiceIme"); assertDefaultEnabledImes(getImesWithoutDefaultVoiceIme(), LOCALE_EN_GB, - "DummyDefaultEnKeyboardIme", "DummyNonDefaultAutoVoiceIme0", - "DummyNonDefaultAutoVoiceIme1"); + "FakeDefaultEnKeyboardIme", "FakeNonDefaultAutoVoiceIme0", + "FakeNonDefaultAutoVoiceIme1"); assertDefaultEnabledMinimumImes(getImesWithDefaultVoiceIme(), LOCALE_EN_GB, - "DummyDefaultEnKeyboardIme"); + "FakeDefaultEnKeyboardIme"); assertDefaultEnabledMinimumImes(getImesWithoutDefaultVoiceIme(), LOCALE_EN_GB, - "DummyDefaultEnKeyboardIme"); + "FakeDefaultEnKeyboardIme"); // locale: ja_JP assertDefaultEnabledImes(getImesWithDefaultVoiceIme(), LOCALE_JA_JP, - "DummyDefaultEnKeyboardIme", "DummyDefaultAutoVoiceIme"); + "FakeDefaultEnKeyboardIme", "FakeDefaultAutoVoiceIme"); assertDefaultEnabledImes(getImesWithoutDefaultVoiceIme(), LOCALE_JA_JP, - "DummyDefaultEnKeyboardIme", "DummyNonDefaultAutoVoiceIme0", - "DummyNonDefaultAutoVoiceIme1"); + "FakeDefaultEnKeyboardIme", "FakeNonDefaultAutoVoiceIme0", + "FakeNonDefaultAutoVoiceIme1"); assertDefaultEnabledMinimumImes(getImesWithDefaultVoiceIme(), LOCALE_JA_JP, - "DummyDefaultEnKeyboardIme"); + "FakeDefaultEnKeyboardIme"); assertDefaultEnabledMinimumImes(getImesWithoutDefaultVoiceIme(), LOCALE_JA_JP, - "DummyDefaultEnKeyboardIme"); + "FakeDefaultEnKeyboardIme"); } @Test @@ -189,67 +189,67 @@ public class InputMethodUtilsTest { @Test public void testGetImplicitlyApplicableSubtypesLocked() throws Exception { - final InputMethodSubtype nonAutoEnUS = createDummyInputMethodSubtype("en_US", + final InputMethodSubtype nonAutoEnUS = createFakeInputMethodSubtype("en_US", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoEnGB = createDummyInputMethodSubtype("en_GB", + final InputMethodSubtype nonAutoEnGB = createFakeInputMethodSubtype("en_GB", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoEnIN = createDummyInputMethodSubtype("en_IN", + final InputMethodSubtype nonAutoEnIN = createFakeInputMethodSubtype("en_IN", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoFrCA = createDummyInputMethodSubtype("fr_CA", + final InputMethodSubtype nonAutoFrCA = createFakeInputMethodSubtype("fr_CA", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoFr = createDummyInputMethodSubtype("fr_CA", + final InputMethodSubtype nonAutoFr = createFakeInputMethodSubtype("fr_CA", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoFil = createDummyInputMethodSubtype("fil", + final InputMethodSubtype nonAutoFil = createFakeInputMethodSubtype("fil", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoIn = createDummyInputMethodSubtype("in", + final InputMethodSubtype nonAutoIn = createFakeInputMethodSubtype("in", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoId = createDummyInputMethodSubtype("id", + final InputMethodSubtype nonAutoId = createFakeInputMethodSubtype("id", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype autoSubtype = createDummyInputMethodSubtype("auto", + final InputMethodSubtype autoSubtype = createFakeInputMethodSubtype("auto", SUBTYPE_MODE_KEYBOARD, !IS_AUX, IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoJa = createDummyInputMethodSubtype("ja", + final InputMethodSubtype nonAutoJa = createFakeInputMethodSubtype("ja", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoHi = createDummyInputMethodSubtype("hi", + final InputMethodSubtype nonAutoHi = createFakeInputMethodSubtype("hi", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoSrCyrl = createDummyInputMethodSubtype("sr", + final InputMethodSubtype nonAutoSrCyrl = createFakeInputMethodSubtype("sr", "sr-Cyrl", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoSrLatn = createDummyInputMethodSubtype("sr_ZZ", + final InputMethodSubtype nonAutoSrLatn = createFakeInputMethodSubtype("sr_ZZ", "sr-Latn", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoHandwritingEn = createDummyInputMethodSubtype("en", + final InputMethodSubtype nonAutoHandwritingEn = createFakeInputMethodSubtype("en", SUBTYPE_MODE_HANDWRITING, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoHandwritingFr = createDummyInputMethodSubtype("fr", + final InputMethodSubtype nonAutoHandwritingFr = createFakeInputMethodSubtype("fr", SUBTYPE_MODE_HANDWRITING, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoHandwritingSrCyrl = createDummyInputMethodSubtype("sr", + final InputMethodSubtype nonAutoHandwritingSrCyrl = createFakeInputMethodSubtype("sr", "sr-Cyrl", SUBTYPE_MODE_HANDWRITING, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoHandwritingSrLatn = createDummyInputMethodSubtype("sr_ZZ", + final InputMethodSubtype nonAutoHandwritingSrLatn = createFakeInputMethodSubtype("sr_ZZ", "sr-Latn", SUBTYPE_MODE_HANDWRITING, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); final InputMethodSubtype nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype = - createDummyInputMethodSubtype("zz", SUBTYPE_MODE_KEYBOARD, !IS_AUX, + createFakeInputMethodSubtype("zz", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); final InputMethodSubtype nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2 = - createDummyInputMethodSubtype("zz", SUBTYPE_MODE_KEYBOARD, !IS_AUX, + createFakeInputMethodSubtype("zz", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); @@ -266,9 +266,9 @@ public class InputMethodUtilsTest { subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2); subtypes.add(nonAutoHandwritingEn); subtypes.add(nonAutoHandwritingFr); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -290,9 +290,9 @@ public class InputMethodUtilsTest { subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2); subtypes.add(nonAutoHandwritingEn); subtypes.add(nonAutoHandwritingFr); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -314,9 +314,9 @@ public class InputMethodUtilsTest { subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype); subtypes.add(nonAutoHandwritingEn); subtypes.add(nonAutoHandwritingFr); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -339,9 +339,9 @@ public class InputMethodUtilsTest { subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2); subtypes.add(nonAutoHandwritingEn); subtypes.add(nonAutoHandwritingFr); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -360,9 +360,9 @@ public class InputMethodUtilsTest { subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2); subtypes.add(nonAutoHandwritingEn); subtypes.add(nonAutoHandwritingFr); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -382,9 +382,9 @@ public class InputMethodUtilsTest { subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2); subtypes.add(nonAutoHandwritingEn); subtypes.add(nonAutoHandwritingFr); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -404,9 +404,9 @@ public class InputMethodUtilsTest { subtypes.add(nonAutoHandwritingEn); subtypes.add(nonAutoHandwritingFr); subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -421,9 +421,9 @@ public class InputMethodUtilsTest { subtypes.add(nonAutoHandwritingEn); subtypes.add(nonAutoHandwritingFr); subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -438,9 +438,9 @@ public class InputMethodUtilsTest { subtypes.add(nonAutoEnUS); subtypes.add(nonAutoHi); subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -460,9 +460,9 @@ public class InputMethodUtilsTest { subtypes.add(nonAutoHandwritingFr); subtypes.add(nonAutoHandwritingSrCyrl); subtypes.add(nonAutoHandwritingSrLatn); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -480,9 +480,9 @@ public class InputMethodUtilsTest { subtypes.add(nonAutoHandwritingFr); subtypes.add(nonAutoHandwritingSrCyrl); subtypes.add(nonAutoHandwritingSrLatn); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -506,9 +506,9 @@ public class InputMethodUtilsTest { subtypes.add(nonAutoHandwritingFr); subtypes.add(nonAutoHandwritingSrCyrl); subtypes.add(nonAutoHandwritingSrLatn); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -533,9 +533,9 @@ public class InputMethodUtilsTest { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); subtypes.add(nonAutoEnUS); subtypes.add(nonAutoFil); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -551,9 +551,9 @@ public class InputMethodUtilsTest { subtypes.add(nonAutoJa); subtypes.add(nonAutoEnUS); subtypes.add(nonAutoFil); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -567,9 +567,9 @@ public class InputMethodUtilsTest { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); subtypes.add(nonAutoIn); subtypes.add(nonAutoEnUS); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -581,9 +581,9 @@ public class InputMethodUtilsTest { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); subtypes.add(nonAutoIn); subtypes.add(nonAutoEnUS); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -595,9 +595,9 @@ public class InputMethodUtilsTest { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); subtypes.add(nonAutoId); subtypes.add(nonAutoEnUS); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -609,9 +609,9 @@ public class InputMethodUtilsTest { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); subtypes.add(nonAutoId); subtypes.add(nonAutoEnUS); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -631,9 +631,9 @@ public class InputMethodUtilsTest { subtypes.add(nonAutoFil); subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype); subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( @@ -649,22 +649,22 @@ public class InputMethodUtilsTest { @Test public void testContainsSubtypeOf() throws Exception { - final InputMethodSubtype nonAutoEnUS = createDummyInputMethodSubtype("en_US", + final InputMethodSubtype nonAutoEnUS = createFakeInputMethodSubtype("en_US", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoEnGB = createDummyInputMethodSubtype("en_GB", + final InputMethodSubtype nonAutoEnGB = createFakeInputMethodSubtype("en_GB", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoFil = createDummyInputMethodSubtype("fil", + final InputMethodSubtype nonAutoFil = createFakeInputMethodSubtype("fil", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoFilPH = createDummyInputMethodSubtype("fil_PH", + final InputMethodSubtype nonAutoFilPH = createFakeInputMethodSubtype("fil_PH", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoIn = createDummyInputMethodSubtype("in", + final InputMethodSubtype nonAutoIn = createFakeInputMethodSubtype("in", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); - final InputMethodSubtype nonAutoId = createDummyInputMethodSubtype("id", + final InputMethodSubtype nonAutoId = createFakeInputMethodSubtype("id", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); @@ -673,9 +673,9 @@ public class InputMethodUtilsTest { { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); subtypes.add(nonAutoEnUS); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN, !CHECK_COUNTRY, @@ -705,9 +705,9 @@ public class InputMethodUtilsTest { { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); subtypes.add(nonAutoFil); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL, !CHECK_COUNTRY, SUBTYPE_MODE_KEYBOARD)); @@ -732,9 +732,9 @@ public class InputMethodUtilsTest { { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); subtypes.add(nonAutoFilPH); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL, !CHECK_COUNTRY, SUBTYPE_MODE_KEYBOARD)); @@ -760,9 +760,9 @@ public class InputMethodUtilsTest { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); subtypes.add(nonAutoIn); subtypes.add(nonAutoEnUS); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, !CHECK_COUNTRY, SUBTYPE_MODE_KEYBOARD)); @@ -779,9 +779,9 @@ public class InputMethodUtilsTest { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); subtypes.add(nonAutoId); subtypes.add(nonAutoEnUS); - final InputMethodInfo imi = createDummyInputMethodInfo( + final InputMethodInfo imi = createFakeInputMethodInfo( "com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT, subtypes); assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, !CHECK_COUNTRY, SUBTYPE_MODE_KEYBOARD)); @@ -866,7 +866,7 @@ public class InputMethodUtilsTest { assertEquals(expected.hashCode(), actual.hashCode()); } - private static InputMethodInfo createDummyInputMethodInfo(String packageName, String name, + private static InputMethodInfo createFakeInputMethodInfo(String packageName, String name, CharSequence label, boolean isAuxIme, boolean isDefault, List<InputMethodSubtype> subtypes) { final ResolveInfo ri = new ResolveInfo(); @@ -885,15 +885,15 @@ public class InputMethodUtilsTest { return new InputMethodInfo(ri, isAuxIme, "", subtypes, 1, isDefault); } - private static InputMethodSubtype createDummyInputMethodSubtype(String locale, String mode, + private static InputMethodSubtype createFakeInputMethodSubtype(String locale, String mode, boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype, boolean isAsciiCapable, boolean isEnabledWhenDefaultIsNotAsciiCapable) { - return createDummyInputMethodSubtype(locale, null /* languageTag */, mode, isAuxiliary, + return createFakeInputMethodSubtype(locale, null /* languageTag */, mode, isAuxiliary, overridesImplicitlyEnabledSubtype, isAsciiCapable, isEnabledWhenDefaultIsNotAsciiCapable); } - private static InputMethodSubtype createDummyInputMethodSubtype(String locale, + private static InputMethodSubtype createFakeInputMethodSubtype(String locale, String languageTag, String mode, boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype, boolean isAsciiCapable, boolean isEnabledWhenDefaultIsNotAsciiCapable) { @@ -920,14 +920,14 @@ public class InputMethodUtilsTest { ArrayList<InputMethodInfo> preinstalledImes = new ArrayList<>(); { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); - subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX, + subtypes.add(createFakeInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX, IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX, + subtypes.add(createFakeInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("DummyDefaultAutoVoiceIme", - "dummy.voice0", "DummyVoice0", IS_AUX, IS_DEFAULT, subtypes)); + preinstalledImes.add(createFakeInputMethodInfo("FakeDefaultAutoVoiceIme", + "fake.voice0", "FakeVoice0", IS_AUX, IS_DEFAULT, subtypes)); } preinstalledImes.addAll(getImesWithoutDefaultVoiceIme()); return preinstalledImes; @@ -937,41 +937,41 @@ public class InputMethodUtilsTest { ArrayList<InputMethodInfo> preinstalledImes = new ArrayList<>(); { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); - subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX, + subtypes.add(createFakeInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX, IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX, + subtypes.add(createFakeInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("DummyNonDefaultAutoVoiceIme0", - "dummy.voice1", "DummyVoice1", IS_AUX, !IS_DEFAULT, subtypes)); + preinstalledImes.add(createFakeInputMethodInfo("FakeNonDefaultAutoVoiceIme0", + "fake.voice1", "FakeVoice1", IS_AUX, !IS_DEFAULT, subtypes)); } { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); - subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX, + subtypes.add(createFakeInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX, IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX, + subtypes.add(createFakeInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("DummyNonDefaultAutoVoiceIme1", - "dummy.voice2", "DummyVoice2", IS_AUX, !IS_DEFAULT, subtypes)); + preinstalledImes.add(createFakeInputMethodInfo("FakeNonDefaultAutoVoiceIme1", + "fake.voice2", "FakeVoice2", IS_AUX, !IS_DEFAULT, subtypes)); } { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); - subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX, + subtypes.add(createFakeInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("DummyNonDefaultVoiceIme2", - "dummy.voice3", "DummyVoice3", IS_AUX, !IS_DEFAULT, subtypes)); + preinstalledImes.add(createFakeInputMethodInfo("FakeNonDefaultVoiceIme2", + "fake.voice3", "FakeVoice3", IS_AUX, !IS_DEFAULT, subtypes)); } { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); - subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_KEYBOARD, !IS_AUX, + subtypes.add(createFakeInputMethodSubtype("en_US", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("DummyDefaultEnKeyboardIme", - "dummy.keyboard0", "DummyKeyboard0", !IS_AUX, IS_DEFAULT, subtypes)); + preinstalledImes.add(createFakeInputMethodInfo("FakeDefaultEnKeyboardIme", + "fake.keyboard0", "FakeKeyboard0", !IS_AUX, IS_DEFAULT, subtypes)); } return preinstalledImes; } @@ -991,91 +991,91 @@ public class InputMethodUtilsTest { private static ArrayList<InputMethodInfo> getSamplePreinstalledImes(final String localeString) { ArrayList<InputMethodInfo> preinstalledImes = new ArrayList<>(); - // a dummy Voice IME + // a fake Voice IME { final boolean isDefaultIme = false; final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); - subtypes.add(createDummyInputMethodSubtype("", SUBTYPE_MODE_VOICE, IS_AUX, + subtypes.add(createFakeInputMethodSubtype("", SUBTYPE_MODE_VOICE, IS_AUX, IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.voice", - "com.android.inputmethod.voice", "DummyVoiceIme", IS_AUX, isDefaultIme, + preinstalledImes.add(createFakeInputMethodInfo("com.android.apps.inputmethod.voice", + "com.android.inputmethod.voice", "FakeVoiceIme", IS_AUX, isDefaultIme, subtypes)); } - // a dummy Hindi IME + // a fake Hindi IME { final boolean isDefaultIme = contains(new String[]{ "hi", "en-rIN" }, localeString); final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); // TODO: This subtype should be marked as IS_ASCII_CAPABLE - subtypes.add(createDummyInputMethodSubtype("en_IN", SUBTYPE_MODE_KEYBOARD, !IS_AUX, + subtypes.add(createFakeInputMethodSubtype("en_IN", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - subtypes.add(createDummyInputMethodSubtype("hi", SUBTYPE_MODE_KEYBOARD, !IS_AUX, + subtypes.add(createFakeInputMethodSubtype("hi", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.hindi", - "com.android.inputmethod.hindi", "DummyHindiIme", !IS_AUX, isDefaultIme, + preinstalledImes.add(createFakeInputMethodInfo("com.android.apps.inputmethod.hindi", + "com.android.inputmethod.hindi", "FakeHindiIme", !IS_AUX, isDefaultIme, subtypes)); } - // a dummy Pinyin IME + // a fake Pinyin IME { final boolean isDefaultIme = contains(new String[]{ "zh-rCN" }, localeString); final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); - subtypes.add(createDummyInputMethodSubtype("zh_CN", SUBTYPE_MODE_KEYBOARD, !IS_AUX, + subtypes.add(createFakeInputMethodSubtype("zh_CN", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.pinyin", - "com.android.apps.inputmethod.pinyin", "DummyPinyinIme", !IS_AUX, isDefaultIme, + preinstalledImes.add(createFakeInputMethodInfo("com.android.apps.inputmethod.pinyin", + "com.android.apps.inputmethod.pinyin", "FakePinyinIme", !IS_AUX, isDefaultIme, subtypes)); } - // a dummy Korean IME + // a fake Korean IME { final boolean isDefaultIme = contains(new String[]{ "ko" }, localeString); final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); - subtypes.add(createDummyInputMethodSubtype("ko", SUBTYPE_MODE_KEYBOARD, !IS_AUX, + subtypes.add(createFakeInputMethodSubtype("ko", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.korean", - "com.android.apps.inputmethod.korean", "DummyKoreanIme", !IS_AUX, isDefaultIme, + preinstalledImes.add(createFakeInputMethodInfo("com.android.apps.inputmethod.korean", + "com.android.apps.inputmethod.korean", "FakeKoreanIme", !IS_AUX, isDefaultIme, subtypes)); } - // a dummy Latin IME + // a fake Latin IME { final boolean isDefaultIme = contains( new String[]{ "en-rUS", "en-rGB", "en-rIN", "en", "hi" }, localeString); final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); - subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_KEYBOARD, !IS_AUX, + subtypes.add(createFakeInputMethodSubtype("en_US", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - subtypes.add(createDummyInputMethodSubtype("en_GB", SUBTYPE_MODE_KEYBOARD, !IS_AUX, + subtypes.add(createFakeInputMethodSubtype("en_GB", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - subtypes.add(createDummyInputMethodSubtype("en_IN", SUBTYPE_MODE_KEYBOARD, !IS_AUX, + subtypes.add(createFakeInputMethodSubtype("en_IN", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - subtypes.add(createDummyInputMethodSubtype("hi", SUBTYPE_MODE_KEYBOARD, !IS_AUX, + subtypes.add(createFakeInputMethodSubtype("hi", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.latin", - "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, isDefaultIme, + preinstalledImes.add(createFakeInputMethodInfo("com.android.apps.inputmethod.latin", + "com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, isDefaultIme, subtypes)); } - // a dummy Japanese IME + // a fake Japanese IME { final boolean isDefaultIme = contains(new String[]{ "ja", "ja-rJP" }, localeString); final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); - subtypes.add(createDummyInputMethodSubtype("ja", SUBTYPE_MODE_KEYBOARD, !IS_AUX, + subtypes.add(createFakeInputMethodSubtype("ja", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - subtypes.add(createDummyInputMethodSubtype("emoji", SUBTYPE_MODE_KEYBOARD, !IS_AUX, + subtypes.add(createFakeInputMethodSubtype("emoji", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)); - preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.japanese", - "com.android.apps.inputmethod.japanese", "DummyJapaneseIme", !IS_AUX, + preinstalledImes.add(createFakeInputMethodInfo("com.android.apps.inputmethod.japanese", + "com.android.apps.inputmethod.japanese", "FakeJapaneseIme", !IS_AUX, isDefaultIme, subtypes)); } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java index 1b5c56a4b4c9..d44d37e4e2a1 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java @@ -19,7 +19,6 @@ package com.android.server.locksettings; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; @@ -169,7 +168,7 @@ public abstract class BaseLockSettingsServiceTests { final ArrayList<UserInfo> allUsers = new ArrayList<>(mPrimaryUserProfiles); allUsers.add(SECONDARY_USER_INFO); - when(mUserManager.getUsers(anyBoolean())).thenReturn(allUsers); + when(mUserManager.getUsers()).thenReturn(allUsers); when(mActivityManager.unlockUser(anyInt(), any(), any(), any())).thenAnswer( new Answer<Boolean>() { diff --git a/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java index 083df28b2278..aaa74dd832af 100644 --- a/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java @@ -284,28 +284,29 @@ public class ThermalManagerServiceTest { @Test public void testNotify() throws RemoteException { int status = Temperature.THROTTLING_SEVERE; + // Should only notify event not status Temperature newBattery = new Temperature(50, Temperature.TYPE_BATTERY, "batt", status); mFakeHal.mCallback.onValues(newBattery); verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) .times(1)).notifyThrottling(newBattery); verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) - .times(1)).onStatusChange(status); + .times(0)).onStatusChange(anyInt()); verify(mEventListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC) .times(0)).notifyThrottling(newBattery); verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC) - .times(1)).onStatusChange(status); + .times(0)).onStatusChange(anyInt()); resetListenerMock(); - // Should only notify event not status + // Notify both event and status Temperature newSkin = new Temperature(50, Temperature.TYPE_SKIN, "skin1", status); mFakeHal.mCallback.onValues(newSkin); verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) .times(1)).notifyThrottling(newSkin); verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) - .times(0)).onStatusChange(anyInt()); + .times(1)).onStatusChange(status); verify(mEventListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC) .times(1)).notifyThrottling(newSkin); verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC) - .times(0)).onStatusChange(anyInt()); + .times(1)).onStatusChange(status); resetListenerMock(); // Back to None, should only notify event not status status = Temperature.THROTTLING_NONE; @@ -345,10 +346,13 @@ public class ThermalManagerServiceTest { @Test public void testGetCurrentStatus() throws RemoteException { - int status = Temperature.THROTTLING_EMERGENCY; + int status = Temperature.THROTTLING_SEVERE; Temperature newSkin = new Temperature(100, Temperature.TYPE_SKIN, "skin1", status); mFakeHal.mCallback.onValues(newSkin); assertEquals(status, mService.mService.getCurrentThermalStatus()); + int battStatus = Temperature.THROTTLING_EMERGENCY; + Temperature newBattery = new Temperature(60, Temperature.TYPE_BATTERY, "batt", battStatus); + assertEquals(status, mService.mService.getCurrentThermalStatus()); } @Test diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java index f9343236662b..7b07102356f0 100644 --- a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java @@ -74,7 +74,7 @@ public class TunerResourceManagerServiceTest { mReclaimed = true; } - public boolean isRelaimed() { + public boolean isReclaimed() { return mReclaimed; } } @@ -387,13 +387,13 @@ public class TunerResourceManagerServiceTest { new TunerFrontendRequest(clientId1[0] /*clientId*/, FrontendSettings.TYPE_DVBT); assertThat(mTunerResourceManagerService .requestFrontendInternal(request, frontendHandle)).isFalse(); - assertThat(listener.isRelaimed()).isFalse(); + assertThat(listener.isReclaimed()).isFalse(); request = new TunerFrontendRequest(clientId1[0] /*clientId*/, FrontendSettings.TYPE_DVBS); assertThat(mTunerResourceManagerService .requestFrontendInternal(request, frontendHandle)).isFalse(); - assertThat(listener.isRelaimed()).isFalse(); + assertThat(listener.isReclaimed()).isFalse(); } @Test @@ -452,7 +452,7 @@ public class TunerResourceManagerServiceTest { .getOwnerClientId()).isEqualTo(clientId1[0]); assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].getId()) .getOwnerClientId()).isEqualTo(clientId1[0]); - assertThat(listener.isRelaimed()).isTrue(); + assertThat(listener.isReclaimed()).isTrue(); } @Test @@ -486,7 +486,7 @@ public class TunerResourceManagerServiceTest { // Release frontend mTunerResourceManagerService.releaseFrontendInternal(mTunerResourceManagerService - .getFrontendResource(frontendId)); + .getFrontendResource(frontendId), clientId[0]); assertThat(mTunerResourceManagerService .getFrontendResource(frontendId).isInUse()).isFalse(); assertThat(mTunerResourceManagerService @@ -548,7 +548,7 @@ public class TunerResourceManagerServiceTest { assertThat(mTunerResourceManagerService.getCasResource(1) .getOwnerClientIds()).isEqualTo(new HashSet<Integer>(Arrays.asList(clientId1[0]))); assertThat(mTunerResourceManagerService.getCasResource(1).isFullyUsed()).isFalse(); - assertThat(listener.isRelaimed()).isTrue(); + assertThat(listener.isReclaimed()).isTrue(); } @Test @@ -633,7 +633,7 @@ public class TunerResourceManagerServiceTest { .isInUse()).isTrue(); assertThat(mTunerResourceManagerService.getLnbResource(lnbIds[0]) .getOwnerClientId()).isEqualTo(clientId1[0]); - assertThat(listener.isRelaimed()).isTrue(); + assertThat(listener.isReclaimed()).isTrue(); assertThat(mTunerResourceManagerService.getClientProfile(clientId0[0]) .getInUseLnbIds().size()).isEqualTo(0); } @@ -761,4 +761,293 @@ public class TunerResourceManagerServiceTest { backgroundRecordProfile)).isEqualTo( (backgroundPlaybackPriority > backgroundRecordPriority)); } + + @Test + public void shareFrontendTest_FrontendWithExclusiveGroupReadyToShare() { + /**** Register Clients and Set Priority ****/ + + // Int array to save the returned client ids + int[] ownerClientId0 = new int[1]; + int[] ownerClientId1 = new int[1]; + int[] shareClientId0 = new int[1]; + int[] shareClientId1 = new int[1]; + + // Predefined client profiles + ResourceClientProfile[] ownerProfiles = new ResourceClientProfile[2]; + ResourceClientProfile[] shareProfiles = new ResourceClientProfile[2]; + ownerProfiles[0] = new ResourceClientProfile( + "0" /*sessionId*/, + TvInputService.PRIORITY_HINT_USE_CASE_TYPE_LIVE); + ownerProfiles[1] = new ResourceClientProfile( + "1" /*sessionId*/, + TvInputService.PRIORITY_HINT_USE_CASE_TYPE_LIVE); + shareProfiles[0] = new ResourceClientProfile( + "2" /*sessionId*/, + TvInputService.PRIORITY_HINT_USE_CASE_TYPE_RECORD); + shareProfiles[1] = new ResourceClientProfile( + "3" /*sessionId*/, + TvInputService.PRIORITY_HINT_USE_CASE_TYPE_RECORD); + + // Predefined client reclaim listeners + TestResourcesReclaimListener ownerListener0 = new TestResourcesReclaimListener(); + TestResourcesReclaimListener shareListener0 = new TestResourcesReclaimListener(); + TestResourcesReclaimListener ownerListener1 = new TestResourcesReclaimListener(); + TestResourcesReclaimListener shareListener1 = new TestResourcesReclaimListener(); + // Register clients and validate the returned client ids + mTunerResourceManagerService + .registerClientProfileInternal(ownerProfiles[0], ownerListener0, ownerClientId0); + mTunerResourceManagerService + .registerClientProfileInternal(shareProfiles[0], shareListener0, shareClientId0); + mTunerResourceManagerService + .registerClientProfileInternal(ownerProfiles[1], ownerListener1, ownerClientId1); + mTunerResourceManagerService + .registerClientProfileInternal(shareProfiles[1], shareListener1, shareClientId1); + assertThat(ownerClientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); + assertThat(shareClientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); + assertThat(ownerClientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); + assertThat(shareClientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); + + mTunerResourceManagerService.updateClientPriorityInternal( + ownerClientId0[0], + 100/*priority*/, + 0/*niceValue*/); + mTunerResourceManagerService.updateClientPriorityInternal( + shareClientId0[0], + 200/*priority*/, + 0/*niceValue*/); + mTunerResourceManagerService.updateClientPriorityInternal( + ownerClientId1[0], + 300/*priority*/, + 0/*niceValue*/); + mTunerResourceManagerService.updateClientPriorityInternal( + shareClientId1[0], + 400/*priority*/, + 0/*niceValue*/); + + /**** Init Frontend Resources ****/ + + // Predefined frontend info + TunerFrontendInfo[] infos = new TunerFrontendInfo[2]; + infos[0] = new TunerFrontendInfo( + 0 /*id*/, + FrontendSettings.TYPE_DVBT, + 1 /*exclusiveGroupId*/); + infos[1] = new TunerFrontendInfo( + 1 /*id*/, + FrontendSettings.TYPE_DVBS, + 1 /*exclusiveGroupId*/); + + /**** Init Lnb Resources ****/ + int[] lnbIds = {1}; + mTunerResourceManagerService.setLnbInfoListInternal(lnbIds); + + // Update frontend list in TRM + mTunerResourceManagerService.setFrontendInfoListInternal(infos); + + /**** Request Frontend ****/ + + // Predefined frontend request and array to save returned frontend handle + int[] frontendHandle = new int[1]; + TunerFrontendRequest request = new TunerFrontendRequest( + ownerClientId0[0] /*clientId*/, + FrontendSettings.TYPE_DVBT); + + // Request call and validate granted resource and internal mapping + assertThat(mTunerResourceManagerService + .requestFrontendInternal(request, frontendHandle)) + .isTrue(); + assertThat(mTunerResourceManagerService + .getResourceIdFromHandle(frontendHandle[0])) + .isEqualTo(infos[0].getId()); + assertThat(mTunerResourceManagerService + .getClientProfile(ownerClientId0[0]) + .getInUseFrontendIds()) + .isEqualTo(new HashSet<Integer>(Arrays.asList( + infos[0].getId(), + infos[1].getId()))); + + /**** Share Frontend ****/ + + // Share frontend call and validate the internal mapping + mTunerResourceManagerService.shareFrontendInternal( + shareClientId0[0]/*selfClientId*/, + ownerClientId0[0]/*targetClientId*/); + mTunerResourceManagerService.shareFrontendInternal( + shareClientId1[0]/*selfClientId*/, + ownerClientId0[0]/*targetClientId*/); + // Verify fe in use status + assertThat(mTunerResourceManagerService.getFrontendResource(infos[0].getId()) + .isInUse()).isTrue(); + assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].getId()) + .isInUse()).isTrue(); + // Verify fe owner status + assertThat(mTunerResourceManagerService.getFrontendResource(infos[0].getId()) + .getOwnerClientId()).isEqualTo(ownerClientId0[0]); + assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].getId()) + .getOwnerClientId()).isEqualTo(ownerClientId0[0]); + // Verify share fe client status in the primary owner client + assertThat(mTunerResourceManagerService.getClientProfile(ownerClientId0[0]) + .getShareFeClientIds()) + .isEqualTo(new HashSet<Integer>(Arrays.asList( + shareClientId0[0], + shareClientId1[0]))); + // Verify in use frontend list in all the primary owner and share owner clients + assertThat(mTunerResourceManagerService + .getClientProfile(ownerClientId0[0]) + .getInUseFrontendIds()) + .isEqualTo(new HashSet<Integer>(Arrays.asList( + infos[0].getId(), + infos[1].getId()))); + assertThat(mTunerResourceManagerService + .getClientProfile(shareClientId0[0]) + .getInUseFrontendIds()) + .isEqualTo(new HashSet<Integer>(Arrays.asList( + infos[0].getId(), + infos[1].getId()))); + assertThat(mTunerResourceManagerService + .getClientProfile(shareClientId1[0]) + .getInUseFrontendIds()) + .isEqualTo(new HashSet<Integer>(Arrays.asList( + infos[0].getId(), + infos[1].getId()))); + + /**** Remove Frontend Share Owner ****/ + + // Unregister the second share fe client + mTunerResourceManagerService.unregisterClientProfileInternal(shareClientId1[0]); + + // Validate the internal mapping + assertThat(mTunerResourceManagerService.getClientProfile(ownerClientId0[0]) + .getShareFeClientIds()) + .isEqualTo(new HashSet<Integer>(Arrays.asList( + shareClientId0[0]))); + assertThat(mTunerResourceManagerService + .getClientProfile(ownerClientId0[0]) + .getInUseFrontendIds()) + .isEqualTo(new HashSet<Integer>(Arrays.asList( + infos[0].getId(), + infos[1].getId()))); + assertThat(mTunerResourceManagerService + .getClientProfile(shareClientId0[0]) + .getInUseFrontendIds()) + .isEqualTo(new HashSet<Integer>(Arrays.asList( + infos[0].getId(), + infos[1].getId()))); + + /**** Request Shared Frontend with Higher Priority Client ****/ + + // Predefined second frontend request + request = new TunerFrontendRequest( + ownerClientId1[0] /*clientId*/, + FrontendSettings.TYPE_DVBT); + + // Second request call + assertThat(mTunerResourceManagerService + .requestFrontendInternal(request, frontendHandle)) + .isTrue(); + + // Validate granted resource and internal mapping + assertThat(mTunerResourceManagerService + .getResourceIdFromHandle(frontendHandle[0])) + .isEqualTo(infos[0].getId()); + assertThat(mTunerResourceManagerService.getFrontendResource(infos[0].getId()) + .getOwnerClientId()).isEqualTo(ownerClientId1[0]); + assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].getId()) + .getOwnerClientId()).isEqualTo(ownerClientId1[0]); + assertThat(mTunerResourceManagerService + .getClientProfile(ownerClientId1[0]) + .getInUseFrontendIds()) + .isEqualTo(new HashSet<Integer>(Arrays.asList( + infos[0].getId(), + infos[1].getId()))); + assertThat(mTunerResourceManagerService + .getClientProfile(ownerClientId0[0]) + .getInUseFrontendIds() + .isEmpty()) + .isTrue(); + assertThat(mTunerResourceManagerService + .getClientProfile(shareClientId0[0]) + .getInUseFrontendIds() + .isEmpty()) + .isTrue(); + assertThat(mTunerResourceManagerService + .getClientProfile(ownerClientId0[0]) + .getShareFeClientIds() + .isEmpty()) + .isTrue(); + assertThat(ownerListener0.isReclaimed()).isTrue(); + assertThat(shareListener0.isReclaimed()).isTrue(); + + /**** Release Frontend Resource From Primary Owner ****/ + + // Reshare the frontend + mTunerResourceManagerService.shareFrontendInternal( + shareClientId0[0]/*selfClientId*/, + ownerClientId1[0]/*targetClientId*/); + + // Release the frontend resource from the primary owner + mTunerResourceManagerService.releaseFrontendInternal(mTunerResourceManagerService + .getFrontendResource(infos[0].getId()), ownerClientId1[0]); + + // Validate the internal mapping + assertThat(mTunerResourceManagerService.getFrontendResource(infos[0].getId()) + .isInUse()).isFalse(); + assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].getId()) + .isInUse()).isFalse(); + // Verify client status + assertThat(mTunerResourceManagerService + .getClientProfile(ownerClientId1[0]) + .getInUseFrontendIds() + .isEmpty()) + .isTrue(); + assertThat(mTunerResourceManagerService + .getClientProfile(shareClientId0[0]) + .getInUseFrontendIds() + .isEmpty()) + .isTrue(); + assertThat(mTunerResourceManagerService + .getClientProfile(ownerClientId1[0]) + .getShareFeClientIds() + .isEmpty()) + .isTrue(); + + /**** Unregister Primary Owner when the Share owner owns an Lnb ****/ + + // Predefined Lnb request and handle array + TunerLnbRequest requestLnb = new TunerLnbRequest(shareClientId0[0]); + int[] lnbHandle = new int[1]; + + // Request for an Lnb + assertThat(mTunerResourceManagerService + .requestLnbInternal(requestLnb, lnbHandle)) + .isTrue(); + + // Request and share the frontend resource again + assertThat(mTunerResourceManagerService + .requestFrontendInternal(request, frontendHandle)) + .isTrue(); + mTunerResourceManagerService.shareFrontendInternal( + shareClientId0[0]/*selfClientId*/, + ownerClientId1[0]/*targetClientId*/); + + // Unregister the primary owner of the shared frontend + mTunerResourceManagerService.unregisterClientProfileInternal(ownerClientId1[0]); + + // Validate the internal mapping + assertThat(mTunerResourceManagerService.getFrontendResource(infos[0].getId()) + .isInUse()).isFalse(); + assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].getId()) + .isInUse()).isFalse(); + // Verify client status + assertThat(mTunerResourceManagerService + .getClientProfile(shareClientId0[0]) + .getInUseFrontendIds() + .isEmpty()) + .isTrue(); + assertThat(mTunerResourceManagerService + .getClientProfile(shareClientId0[0]) + .getInUseLnbIds()) + .isEqualTo(new HashSet<Integer>(Arrays.asList( + lnbIds[0]))); + } } diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java index 4dec7a1a0ab9..7c7b1a296673 100644 --- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java @@ -1383,7 +1383,7 @@ public class AppStandbyControllerTests { getStandbyBucket(mController, PACKAGE_1)); mController.postReportSyncScheduled(PACKAGE_1, USER_ID, false); - mStateChangedLatch.await(100, TimeUnit.MILLISECONDS); + mStateChangedLatch.await(1000, TimeUnit.MILLISECONDS); assertEquals("Unexempted sync scheduled should bring the package out of the Never bucket", STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController, PACKAGE_1)); @@ -1391,7 +1391,7 @@ public class AppStandbyControllerTests { mStateChangedLatch = new CountDownLatch(1); mController.postReportSyncScheduled(PACKAGE_1, USER_ID, false); - mStateChangedLatch.await(100, TimeUnit.MILLISECONDS); + mStateChangedLatch.await(1000, TimeUnit.MILLISECONDS); assertEquals("Unexempted sync scheduled should not elevate a non Never bucket", STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1)); } @@ -1402,7 +1402,7 @@ public class AppStandbyControllerTests { mInjector.mDeviceIdleMode = true; mStateChangedLatch = new CountDownLatch(1); mController.postReportSyncScheduled(PACKAGE_1, USER_ID, true); - mStateChangedLatch.await(100, TimeUnit.MILLISECONDS); + mStateChangedLatch.await(1000, TimeUnit.MILLISECONDS); assertEquals("Exempted sync scheduled in doze should set bucket to working set", STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController, PACKAGE_1)); @@ -1410,7 +1410,7 @@ public class AppStandbyControllerTests { mInjector.mDeviceIdleMode = false; mStateChangedLatch = new CountDownLatch(1); mController.postReportSyncScheduled(PACKAGE_1, USER_ID, true); - mStateChangedLatch.await(100, TimeUnit.MILLISECONDS); + mStateChangedLatch.await(1000, TimeUnit.MILLISECONDS); assertEquals("Exempted sync scheduled while not in doze should set bucket to active", STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1)); } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 5b2d738eb760..9319bea497fb 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -3886,7 +3886,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mService.updateUriPermissions(recordB, recordA, mContext.getPackageName(), USER_SYSTEM); verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner(any(), - eq(message1.getDataUri()), anyInt(), anyInt()); + eq(message1.getDataUri()), anyInt(), anyInt(), eq(null), eq(-1)); // Update back means we grant access to first again reset(mUgm); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java index 96b970056c98..1e95aba0c2d7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java @@ -192,6 +192,8 @@ public class ActivityStackSupervisorTests extends WindowTestsBase { virtualDisplay.getDisplay().getDisplayId(), unresizableActivity.info); assertThat(allowed).isTrue(); + + virtualDisplay.release(); } @Test @@ -206,6 +208,8 @@ public class ActivityStackSupervisorTests extends WindowTestsBase { virtualDisplay.getDisplay().getDisplayId(), unresizableActivity.info); assertThat(allowed).isFalse(); + + virtualDisplay.release(); } private VirtualDisplay createVirtualDisplay(boolean trusted) { diff --git a/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java b/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java index 8223024234fb..578a43cba33d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java @@ -38,13 +38,13 @@ import org.junit.Test; */ @SmallTest @Presubmit -@Ignore("b/163095037") public class ProtoLogIntegrationTest { @After public void tearDown() { ProtoLogImpl.setSingleInstance(null); } + @Ignore("b/163095037") @Test public void testProtoLogToolIntegration() { ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java index 2f736555ae1b..189e540af0ca 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java @@ -16,6 +16,8 @@ package com.android.server.wm; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.view.Display.INVALID_DISPLAY; @@ -253,6 +255,19 @@ public class WindowProcessControllerTests extends WindowTestsBase { assertFalse(mWpc.registeredForActivityConfigChanges()); } + @Test + public void testProcessLevelConfiguration() { + Configuration config = new Configuration(); + config.windowConfiguration.setActivityType(ACTIVITY_TYPE_HOME); + mWpc.onRequestedOverrideConfigurationChanged(config); + assertEquals(ACTIVITY_TYPE_HOME, config.windowConfiguration.getActivityType()); + assertEquals(ACTIVITY_TYPE_UNDEFINED, mWpc.getActivityType()); + + mWpc.onMergedOverrideConfigurationChanged(config); + assertEquals(ACTIVITY_TYPE_HOME, config.windowConfiguration.getActivityType()); + assertEquals(ACTIVITY_TYPE_UNDEFINED, mWpc.getActivityType()); + } + private TestDisplayContent createTestDisplayContentInContainer() { return new TestDisplayContent.Builder(mAtm, 1000, 1500).build(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java index d9c48fc4ba37..e0785c13a336 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java @@ -27,6 +27,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -145,29 +146,40 @@ public class WindowTokenTests extends WindowTestsBase { assertEquals(0, token.getWindowsCount()); } - @UseTestDisplay(addWindows = { W_ACTIVITY, W_WALLPAPER }) @Test public void testFinishFixedRotationTransform() { - final WindowToken appToken = mAppWindow.mToken; - final WindowToken wallpaperToken = mWallpaperWindow.mToken; + final WindowToken[] tokens = new WindowToken[3]; + for (int i = 0; i < tokens.length; i++) { + tokens[i] = createTestWindowToken(TYPE_APPLICATION_OVERLAY, mDisplayContent); + } + final Configuration config = new Configuration(mDisplayContent.getConfiguration()); final int originalRotation = config.windowConfiguration.getRotation(); final int targetRotation = (originalRotation + 1) % 4; config.windowConfiguration.setRotation(targetRotation); - appToken.applyFixedRotationTransform(mDisplayInfo, mDisplayContent.mDisplayFrames, config); - wallpaperToken.linkFixedRotationTransform(appToken); + tokens[0].applyFixedRotationTransform(mDisplayInfo, mDisplayContent.mDisplayFrames, config); + tokens[1].linkFixedRotationTransform(tokens[0]); // The window tokens should apply the rotation by the transformation. - assertEquals(targetRotation, appToken.getWindowConfiguration().getRotation()); - assertEquals(targetRotation, wallpaperToken.getWindowConfiguration().getRotation()); + assertEquals(targetRotation, tokens[0].getWindowConfiguration().getRotation()); + assertEquals(targetRotation, tokens[1].getWindowConfiguration().getRotation()); + + tokens[2].applyFixedRotationTransform(mDisplayInfo, mDisplayContent.mDisplayFrames, config); + // The tokens[1] was linked to tokens[0], this should make tokens[1] link to tokens[2]. + tokens[1].linkFixedRotationTransform(tokens[2]); + + // Assume the display doesn't rotate, the transformation will be canceled. + tokens[0].finishFixedRotationTransform(); - // The display doesn't rotate, the transformation will be canceled. - mAppWindow.mToken.finishFixedRotationTransform(); + // The tokens[0] should restore to the original rotation. + assertEquals(originalRotation, tokens[0].getWindowConfiguration().getRotation()); + // The tokens[1] is linked to tokens[2], it should keep the target rotation. + assertNotEquals(originalRotation, tokens[1].getWindowConfiguration().getRotation()); - // The window tokens should restore to the original rotation. - assertEquals(originalRotation, appToken.getWindowConfiguration().getRotation()); - assertEquals(originalRotation, wallpaperToken.getWindowConfiguration().getRotation()); + tokens[2].finishFixedRotationTransform(); + // The rotation of tokens[1] should be restored because its linked state is finished. + assertEquals(originalRotation, tokens[1].getWindowConfiguration().getRotation()); } /** diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 78556ef41edb..1e5d92b270d2 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -61,7 +61,6 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ParceledListSlice; import android.content.pm.ShortcutServiceInternal; -import android.content.pm.UserInfo; import android.content.res.Configuration; import android.os.Binder; import android.os.Environment; @@ -306,25 +305,25 @@ public class UsageStatsService extends SystemService implements @Override public void onUserStopping(@NonNull TargetUser user) { - final UserInfo userInfo = user.getUserInfo(); + final int userId = user.getUserIdentifier(); synchronized (mLock) { // User was started but never unlocked so no need to report a user stopped event - if (!mUserUnlockedStates.get(userInfo.id)) { - persistPendingEventsLocked(userInfo.id); + if (!mUserUnlockedStates.get(userId)) { + persistPendingEventsLocked(userId); return; } // Report a user stopped event before persisting all stats to disk via the user service final Event event = new Event(USER_STOPPED, SystemClock.elapsedRealtime()); event.mPackage = Event.DEVICE_EVENT_PACKAGE_NAME; - reportEvent(event, userInfo.id); - final UserUsageStatsService userService = mUserState.get(userInfo.id); + reportEvent(event, userId); + final UserUsageStatsService userService = mUserState.get(userId); if (userService != null) { userService.userStopped(); } - mUserUnlockedStates.put(userInfo.id, false); - mUserState.put(userInfo.id, null); // release the service (mainly for GC) + mUserUnlockedStates.put(userId, false); + mUserState.put(userId, null); // release the service (mainly for GC) } } diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index 0f898f8e679e..a2215ceed36a 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -164,13 +164,13 @@ public class VoiceInteractionManagerService extends SystemService { } } - private boolean isSupported(UserInfo user) { + @Override + public boolean isUserSupported(@NonNull TargetUser user) { return user.isFull(); } - @Override - public boolean isUserSupported(TargetUser user) { - return isSupported(user.getUserInfo()); + private boolean isUserSupported(@NonNull UserInfo user) { + return user.isFull(); } @Override @@ -461,7 +461,7 @@ public class VoiceInteractionManagerService extends SystemService { private void setCurrentUserLocked(@UserIdInt int userHandle) { mCurUser = userHandle; final UserInfo userInfo = mUserManagerInternal.getUserInfo(mCurUser); - mCurUserSupported = isSupported(userInfo); + mCurUserSupported = isUserSupported(userInfo); } public void switchUser(@UserIdInt int userHandle) { @@ -967,10 +967,10 @@ public class VoiceInteractionManagerService extends SystemService { throw new IllegalArgumentException("Illegal argument(s) in getKeyphraseSoundModel"); } - final int callingUid = UserHandle.getCallingUserId(); + final int callingUserId = UserHandle.getCallingUserId(); final long caller = Binder.clearCallingIdentity(); try { - return mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); + return mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUserId, bcp47Locale); } finally { Binder.restoreCallingIdentity(caller); } @@ -1010,7 +1010,7 @@ public class VoiceInteractionManagerService extends SystemService { "Illegal argument(s) in deleteKeyphraseSoundModel"); } - final int callingUid = UserHandle.getCallingUserId(); + final int callingUserId = UserHandle.getCallingUserId(); final long caller = Binder.clearCallingIdentity(); boolean deleted = false; try { @@ -1018,7 +1018,8 @@ public class VoiceInteractionManagerService extends SystemService { if (unloadStatus != SoundTriggerInternal.STATUS_OK) { Slog.w(TAG, "Unable to unload keyphrase sound model:" + unloadStatus); } - deleted = mDbHelper.deleteKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); + deleted = mDbHelper.deleteKeyphraseSoundModel( + keyphraseId, callingUserId, bcp47Locale); return deleted ? SoundTriggerInternal.STATUS_OK : SoundTriggerInternal.STATUS_ERROR; } finally { if (deleted) { @@ -1045,11 +1046,11 @@ public class VoiceInteractionManagerService extends SystemService { throw new IllegalArgumentException("Illegal argument(s) in isEnrolledForKeyphrase"); } - final int callingUid = UserHandle.getCallingUserId(); + final int callingUserId = UserHandle.getCallingUserId(); final long caller = Binder.clearCallingIdentity(); try { KeyphraseSoundModel model = - mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); + mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUserId, bcp47Locale); return model != null; } finally { Binder.restoreCallingIdentity(caller); @@ -1067,11 +1068,11 @@ public class VoiceInteractionManagerService extends SystemService { throw new IllegalArgumentException("Illegal argument(s) in isEnrolledForKeyphrase"); } - final int callingUid = UserHandle.getCallingUserId(); + final int callingUserId = UserHandle.getCallingUserId(); final long caller = Binder.clearCallingIdentity(); try { KeyphraseSoundModel model = - mDbHelper.getKeyphraseSoundModel(keyphrase, callingUid, bcp47Locale); + mDbHelper.getKeyphraseSoundModel(keyphrase, callingUserId, bcp47Locale); if (model == null) { return null; } @@ -1118,11 +1119,11 @@ public class VoiceInteractionManagerService extends SystemService { } } - int callingUid = UserHandle.getCallingUserId(); + final int callingUserId = UserHandle.getCallingUserId(); final long caller = Binder.clearCallingIdentity(); try { KeyphraseSoundModel soundModel = - mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUid, bcp47Locale); + mDbHelper.getKeyphraseSoundModel(keyphraseId, callingUserId, bcp47Locale); if (soundModel == null || soundModel.getUuid() == null || soundModel.getKeyphrases() == null) { diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java index 3646647e9734..6288bc1698e9 100755 --- a/telecomm/java/android/telecom/ConnectionService.java +++ b/telecomm/java/android/telecom/ConnectionService.java @@ -2488,6 +2488,42 @@ public abstract class ConnectionService extends Service { } /** + * Ask some other {@code ConnectionService} to create a {@code RemoteConference} given an + * incoming request. This is used by {@code ConnectionService}s that are registered with + * {@link PhoneAccount#CAPABILITY_ADHOC_CONFERENCE_CALLING}. + * + * @param connectionManagerPhoneAccount See description at + * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}. + * @param request Details about the incoming conference call. + * @return The {@code RemoteConference} object to satisfy this call, or {@code null} to not + * handle the call. + */ + public final @Nullable RemoteConference createRemoteIncomingConference( + @Nullable PhoneAccountHandle connectionManagerPhoneAccount, + @Nullable ConnectionRequest request) { + return mRemoteConnectionManager.createRemoteConference(connectionManagerPhoneAccount, + request, true); + } + + /** + * Ask some other {@code ConnectionService} to create a {@code RemoteConference} given an + * outgoing request. This is used by {@code ConnectionService}s that are registered with + * {@link PhoneAccount#CAPABILITY_ADHOC_CONFERENCE_CALLING}. + * + * @param connectionManagerPhoneAccount See description at + * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}. + * @param request Details about the outgoing conference call. + * @return The {@code RemoteConference} object to satisfy this call, or {@code null} to not + * handle the call. + */ + public final @Nullable RemoteConference createRemoteOutgoingConference( + @Nullable PhoneAccountHandle connectionManagerPhoneAccount, + @Nullable ConnectionRequest request) { + return mRemoteConnectionManager.createRemoteConference(connectionManagerPhoneAccount, + request, false); + } + + /** * Indicates to the relevant {@code RemoteConnectionService} that the specified * {@link RemoteConnection}s should be merged into a conference call. * <p> diff --git a/telecomm/java/android/telecom/RemoteConference.java b/telecomm/java/android/telecom/RemoteConference.java index 502b7c01b0c0..e024e6186519 100644 --- a/telecomm/java/android/telecom/RemoteConference.java +++ b/telecomm/java/android/telecom/RemoteConference.java @@ -16,14 +16,14 @@ package android.telecom; -import com.android.internal.telecom.IConnectionService; - import android.annotation.Nullable; import android.annotation.SystemApi; import android.os.Bundle; import android.os.Handler; import android.os.RemoteException; +import com.android.internal.telecom.IConnectionService; + import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -155,6 +155,14 @@ public final class RemoteConference { } /** @hide */ + RemoteConference(DisconnectCause disconnectCause) { + mId = "NULL"; + mConnectionService = null; + mState = Connection.STATE_DISCONNECTED; + mDisconnectCause = disconnectCause; + } + + /** @hide */ String getId() { return mId; } @@ -583,4 +591,16 @@ public final class RemoteConference { } } } + + /** + * Create a {@link RemoteConference} represents a failure, and which will + * be in {@link Connection#STATE_DISCONNECTED}. + * + * @param disconnectCause The disconnect cause. + * @return a failed {@link RemoteConference} + * @hide + */ + public static RemoteConference failure(DisconnectCause disconnectCause) { + return new RemoteConference(disconnectCause); + } } diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java index df3362578680..52210a55c8d0 100644 --- a/telecomm/java/android/telecom/RemoteConnection.java +++ b/telecomm/java/android/telecom/RemoteConnection.java @@ -16,10 +16,6 @@ package android.telecom; -import com.android.internal.telecom.IConnectionService; -import com.android.internal.telecom.IVideoCallback; -import com.android.internal.telecom.IVideoProvider; - import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; @@ -33,6 +29,10 @@ import android.os.RemoteException; import android.telecom.Logging.Session; import android.view.Surface; +import com.android.internal.telecom.IConnectionService; +import com.android.internal.telecom.IVideoCallback; +import com.android.internal.telecom.IVideoProvider; + import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -1114,6 +1114,23 @@ public final class RemoteConnection { } /** + * Instructs this {@link RemoteConnection} to initiate a conference with a list of + * participants. + * <p> + * + * @param participants with which conference call will be formed. + */ + public void addConferenceParticipants(@NonNull List<Uri> participants) { + try { + if (mConnected) { + mConnectionService.addConferenceParticipants(mConnectionId, participants, + null /*Session.Info*/); + } + } catch (RemoteException ignored) { + } + } + + /** * Set the audio state of this {@code RemoteConnection}. * * @param state The audio state of this {@code RemoteConnection}. diff --git a/telecomm/java/android/telecom/RemoteConnectionManager.java b/telecomm/java/android/telecom/RemoteConnectionManager.java index 0322218d75dc..f3c7bd83ed4b 100644 --- a/telecomm/java/android/telecom/RemoteConnectionManager.java +++ b/telecomm/java/android/telecom/RemoteConnectionManager.java @@ -73,6 +73,37 @@ public class RemoteConnectionManager { return null; } + /** + * Ask a {@code RemoteConnectionService} to create a {@code RemoteConference}. + * @param connectionManagerPhoneAccount See description at + * {@link ConnectionService#onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}. + * @param request Details about the incoming conference call. + * @param isIncoming {@code true} if it's an incoming conference. + * @return + */ + public RemoteConference createRemoteConference( + PhoneAccountHandle connectionManagerPhoneAccount, + ConnectionRequest request, + boolean isIncoming) { + PhoneAccountHandle accountHandle = request.getAccountHandle(); + if (accountHandle == null) { + throw new IllegalArgumentException("accountHandle must be specified."); + } + + ComponentName componentName = request.getAccountHandle().getComponentName(); + if (!mRemoteConnectionServices.containsKey(componentName)) { + throw new UnsupportedOperationException("accountHandle not supported: " + + componentName); + } + + RemoteConnectionService remoteService = mRemoteConnectionServices.get(componentName); + if (remoteService != null) { + return remoteService.createRemoteConference( + connectionManagerPhoneAccount, request, isIncoming); + } + return null; + } + public void conferenceRemoteConnections(RemoteConnection a, RemoteConnection b) { if (a.getConnectionService() == b.getConnectionService()) { try { diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java index a0833011715d..bf6a6ef793ff 100644 --- a/telecomm/java/android/telecom/RemoteConnectionService.java +++ b/telecomm/java/android/telecom/RemoteConnectionService.java @@ -31,9 +31,9 @@ import com.android.internal.telecom.RemoteServiceCallback; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; -import java.util.List; import java.util.UUID; /** @@ -591,6 +591,38 @@ final class RemoteConnectionService { } } + RemoteConference createRemoteConference( + PhoneAccountHandle connectionManagerPhoneAccount, + ConnectionRequest request, + boolean isIncoming) { + final String id = UUID.randomUUID().toString(); + try { + if (mConferenceById.isEmpty()) { + mOutgoingConnectionServiceRpc.addConnectionServiceAdapter(mServant.getStub(), + null /*Session.Info*/); + } + RemoteConference conference = new RemoteConference(id, mOutgoingConnectionServiceRpc); + mOutgoingConnectionServiceRpc.createConference(connectionManagerPhoneAccount, + id, + request, + isIncoming, + false /* isUnknownCall */, + null /*Session.info*/); + conference.registerCallback(new RemoteConference.Callback() { + @Override + public void onDestroyed(RemoteConference conference) { + mConferenceById.remove(id); + maybeDisconnectAdapter(); + } + }); + conference.putExtras(request.getExtras()); + return conference; + } catch (RemoteException e) { + return RemoteConference.failure( + new DisconnectCause(DisconnectCause.ERROR, e.toString())); + } + } + private boolean hasConnection(String callId) { return mConnectionById.containsKey(callId); } diff --git a/telephony/common/com/android/internal/telephony/CarrierAppUtils.java b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java index e57b03098758..d4308c4c30ad 100644 --- a/telephony/common/com/android/internal/telephony/CarrierAppUtils.java +++ b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java @@ -17,6 +17,7 @@ package com.android.internal.telephony; import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.content.ContentResolver; import android.content.Context; import android.content.pm.ApplicationInfo; @@ -74,7 +75,7 @@ public final class CarrierAppUtils { * privileged apps may have changed. */ public static synchronized void disableCarrierAppsUntilPrivileged(String callingPackage, - TelephonyManager telephonyManager, int userId, Context context) { + TelephonyManager telephonyManager, @UserIdInt int userId, Context context) { if (DEBUG) { Log.d(TAG, "disableCarrierAppsUntilPrivileged"); } @@ -101,7 +102,7 @@ public final class CarrierAppUtils { * Manager can kill it, and this can lead to crashes as the app is in an unexpected state. */ public static synchronized void disableCarrierAppsUntilPrivileged(String callingPackage, - int userId, Context context) { + @UserIdInt int userId, Context context) { if (DEBUG) { Log.d(TAG, "disableCarrierAppsUntilPrivileged"); } @@ -117,9 +118,9 @@ public final class CarrierAppUtils { systemCarrierAssociatedAppsDisabledUntilUsed, context); } - private static ContentResolver getContentResolverForUser(Context context, int userId) { - Context userContext = context.createContextAsUser(UserHandle.getUserHandleForUid(userId), - 0); + private static ContentResolver getContentResolverForUser(Context context, + @UserIdInt int userId) { + Context userContext = context.createContextAsUser(UserHandle.of(userId), 0); return userContext.getContentResolver(); } diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index 2b2608724e12..78dc377a303c 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -46,6 +46,7 @@ import com.android.internal.telephony.IIntegerConsumer; import com.android.internal.telephony.ISms; import com.android.internal.telephony.ITelephony; import com.android.internal.telephony.SmsRawData; +import com.android.telephony.Rlog; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -1953,7 +1954,6 @@ public final class SmsManager { public boolean enableCellBroadcastRange(int startMessageId, int endMessageId, @android.telephony.SmsCbMessage.MessageFormat int ranType) { boolean success = false; - if (endMessageId < startMessageId) { throw new IllegalArgumentException("endMessageId < startMessageId"); } @@ -1962,10 +1962,14 @@ public final class SmsManager { if (iSms != null) { // If getSubscriptionId() returns INVALID or an inactive subscription, we will use // the default phone internally. - success = iSms.enableCellBroadcastRangeForSubscriber(getSubscriptionId(), + int subId = getSubscriptionId(); + success = iSms.enableCellBroadcastRangeForSubscriber(subId, startMessageId, endMessageId, ranType); + Rlog.d(TAG, "enableCellBroadcastRange: " + (success ? "succeeded" : "failed") + + " at calling enableCellBroadcastRangeForSubscriber. subId = " + subId); } } catch (RemoteException ex) { + Rlog.d(TAG, "enableCellBroadcastRange: " + ex.getStackTrace()); // ignore it } @@ -2019,10 +2023,14 @@ public final class SmsManager { if (iSms != null) { // If getSubscriptionId() returns INVALID or an inactive subscription, we will use // the default phone internally. - success = iSms.disableCellBroadcastRangeForSubscriber(getSubscriptionId(), + int subId = getSubscriptionId(); + success = iSms.disableCellBroadcastRangeForSubscriber(subId, startMessageId, endMessageId, ranType); + Rlog.d(TAG, "disableCellBroadcastRange: " + (success ? "succeeded" : "failed") + + " at calling disableCellBroadcastRangeForSubscriber. subId = " + subId); } } catch (RemoteException ex) { + Rlog.d(TAG, "disableCellBroadcastRange: " + ex.getStackTrace()); // ignore it } diff --git a/telephony/java/android/telephony/ims/ImsConferenceState.java b/telephony/java/android/telephony/ims/ImsConferenceState.java index 21bef001efae..9bf2f44395c4 100644 --- a/telephony/java/android/telephony/ims/ImsConferenceState.java +++ b/telephony/java/android/telephony/ims/ImsConferenceState.java @@ -203,10 +203,10 @@ public final class ImsConferenceState implements Parcelable { for (String key : participantData.keySet()) { sb.append(key); sb.append("="); - if (ENDPOINT.equals(key) || USER.equals(key)) { - sb.append(Rlog.pii(TAG, participantData.get(key))); - } else { + if (STATUS.equals(key)) { sb.append(participantData.get(key)); + } else { + sb.append(Rlog.pii(TAG, participantData.get(key))); } sb.append(", "); } diff --git a/tests/RollbackTest/README.txt b/tests/RollbackTest/README.txt index c0b718a3e2c1..bc3b3bc3a1ee 100644 --- a/tests/RollbackTest/README.txt +++ b/tests/RollbackTest/README.txt @@ -9,10 +9,10 @@ StagedRollbackTest - device driven test for staged rollbacks. TestApp - - source for dummy apks used in testing. + - source for fake apks used in testing. TestApex - - source for dummy apex modules used in testing. + - source for fake apex modules used in testing. Running the tests ================= diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp index 530d0e492f2e..76f8df02465b 100644 --- a/tests/StagedInstallTest/Android.bp +++ b/tests/StagedInstallTest/Android.bp @@ -18,6 +18,9 @@ android_test_helper_app { srcs: ["app/src/**/*.java"], static_libs: ["androidx.test.rules", "cts-install-lib"], test_suites: ["general-tests"], + java_resources: [ + ":com.android.apex.apkrollback.test_v2", + ], } java_test_host { diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java index 02597d548361..12f1750fb78c 100644 --- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java +++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java @@ -49,6 +49,11 @@ import java.util.function.Consumer; public class StagedInstallInternalTest { private static final String TAG = StagedInstallInternalTest.class.getSimpleName(); + private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test"; + private static final TestApp TEST_APEX_WITH_APK_V1 = new TestApp("TestApexWithApkV1", + APK_IN_APEX_TESTAPEX_NAME, 1, /*isApex*/true, APK_IN_APEX_TESTAPEX_NAME + "_v1.apex"); + private static final TestApp TEST_APEX_WITH_APK_V2 = new TestApp("TestApexWithApkV2", + APK_IN_APEX_TESTAPEX_NAME, 2, /*isApex*/true, APK_IN_APEX_TESTAPEX_NAME + "_v2.apex"); private File mTestStateFile = new File( InstrumentationRegistry.getInstrumentation().getContext().getFilesDir(), @@ -82,6 +87,24 @@ public class StagedInstallInternalTest { } @Test + public void testDuplicateApkInApexShouldFail_Commit() throws Exception { + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1); + // Duplicate packages(TestApp.A) in TEST_APEX_WITH_APK_V2(apk-in-apex) and TestApp.A2(apk) + // should fail to install. + int sessionId = Install.multi(TEST_APEX_WITH_APK_V2, TestApp.A2).setStaged().commit(); + storeSessionId(sessionId); + } + + @Test + public void testDuplicateApkInApexShouldFail_Verify() throws Exception { + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1); + int sessionId = retrieveLastSessionId(); + PackageInstaller.SessionInfo info = + InstallUtils.getPackageInstaller().getSessionInfo(sessionId); + assertThat(info.isStagedSessionFailed()).isTrue(); + } + + @Test public void testSystemServerRestartDoesNotAffectStagedSessions_Commit() throws Exception { int sessionId = Install.single(TestApp.A1).setStaged().commit(); assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1); diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java index 55def498a0cd..792e29d93be2 100644 --- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java +++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java @@ -24,11 +24,14 @@ import static org.junit.Assume.assumeTrue; import android.cts.install.lib.host.InstallUtilsHost; +import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper; import com.android.ddmlib.Log; import com.android.tests.rollback.host.AbandonSessionsRule; import com.android.tests.util.ModuleTestUtils; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; +import com.android.tradefed.util.CommandResult; +import com.android.tradefed.util.CommandStatus; import com.android.tradefed.util.ProcessInfo; import org.junit.After; @@ -49,6 +52,7 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { public AbandonSessionsRule mHostTestRule = new AbandonSessionsRule(this); private static final String SHIM_V2 = "com.android.apex.cts.shim.v2.apex"; private static final String APK_A = "TestAppAv1.apk"; + private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test"; private final ModuleTestUtils mTestUtils = new ModuleTestUtils(this); private final InstallUtilsHost mHostUtils = new InstallUtilsHost(this); @@ -74,6 +78,8 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { } catch (AssertionError e) { Log.e(TAG, e); } + deleteFiles("/system/apex/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex", + "/data/apex/active/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex"); } @Before @@ -86,6 +92,55 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { cleanUp(); } + /** + * Deletes files and reboots the device if necessary. + * @param files the paths of files which might contain wildcards + */ + private void deleteFiles(String... files) throws Exception { + boolean found = false; + for (String file : files) { + CommandResult result = getDevice().executeShellV2Command("ls " + file); + if (result.getStatus() == CommandStatus.SUCCESS) { + found = true; + break; + } + } + + if (found) { + if (!getDevice().isAdbRoot()) { + getDevice().enableAdbRoot(); + } + getDevice().remountSystemWritable(); + for (String file : files) { + getDevice().executeShellCommand("rm -rf " + file); + } + getDevice().reboot(); + } + } + + private void pushTestApex() throws Exception { + CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild()); + final String fileName = APK_IN_APEX_TESTAPEX_NAME + "_v1.apex"; + final File apex = buildHelper.getTestFile(fileName); + if (!getDevice().isAdbRoot()) { + getDevice().enableAdbRoot(); + } + getDevice().remountSystemWritable(); + assertTrue(getDevice().pushFile(apex, "/system/apex/" + fileName)); + getDevice().reboot(); + } + + /** + * Tests that duplicate packages in apk-in-apex and apk should fail to install. + */ + @Test + public void testDuplicateApkInApexShouldFail() throws Exception { + pushTestApex(); + runPhase("testDuplicateApkInApexShouldFail_Commit"); + getDevice().reboot(); + runPhase("testDuplicateApkInApexShouldFail_Verify"); + } + @Test public void testSystemServerRestartDoesNotAffectStagedSessions() throws Exception { runPhase("testSystemServerRestartDoesNotAffectStagedSessions_Commit"); diff --git a/tests/net/common/java/android/net/DhcpInfoTest.java b/tests/net/common/java/android/net/DhcpInfoTest.java index 4d45ad72a9b8..ab4726bab573 100644 --- a/tests/net/common/java/android/net/DhcpInfoTest.java +++ b/tests/net/common/java/android/net/DhcpInfoTest.java @@ -17,8 +17,8 @@ package android.net; import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTL; -import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals; -import static com.android.testutils.ParcelUtilsKt.parcelingRoundTrip; +import static com.android.testutils.MiscAsserts.assertFieldCountEquals; +import static com.android.testutils.ParcelUtils.parcelingRoundTrip; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; diff --git a/tests/net/common/java/android/net/IpPrefixTest.java b/tests/net/common/java/android/net/IpPrefixTest.java index 985e10df3961..9c0fc7ce7881 100644 --- a/tests/net/common/java/android/net/IpPrefixTest.java +++ b/tests/net/common/java/android/net/IpPrefixTest.java @@ -16,10 +16,10 @@ package android.net; -import static com.android.testutils.MiscAssertsKt.assertEqualBothWays; -import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals; -import static com.android.testutils.MiscAssertsKt.assertNotEqualEitherWay; -import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless; +import static com.android.testutils.MiscAsserts.assertEqualBothWays; +import static com.android.testutils.MiscAsserts.assertFieldCountEquals; +import static com.android.testutils.MiscAsserts.assertNotEqualEitherWay; +import static com.android.testutils.ParcelUtils.assertParcelingIsLossless; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; diff --git a/tests/net/common/java/android/net/LinkAddressTest.java b/tests/net/common/java/android/net/LinkAddressTest.java index c74c112490f8..60308e32b88d 100644 --- a/tests/net/common/java/android/net/LinkAddressTest.java +++ b/tests/net/common/java/android/net/LinkAddressTest.java @@ -27,10 +27,10 @@ import static android.system.OsConstants.RT_SCOPE_LINK; import static android.system.OsConstants.RT_SCOPE_SITE; import static android.system.OsConstants.RT_SCOPE_UNIVERSE; -import static com.android.testutils.MiscAssertsKt.assertEqualBothWays; -import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals; -import static com.android.testutils.MiscAssertsKt.assertNotEqualEitherWay; -import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless; +import static com.android.testutils.MiscAsserts.assertEqualBothWays; +import static com.android.testutils.MiscAsserts.assertFieldCountEquals; +import static com.android.testutils.MiscAsserts.assertNotEqualEitherWay; +import static com.android.testutils.ParcelUtils.assertParcelingIsLossless; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java index 6eba62e63740..3c3076f11727 100644 --- a/tests/net/common/java/android/net/LinkPropertiesTest.java +++ b/tests/net/common/java/android/net/LinkPropertiesTest.java @@ -20,9 +20,9 @@ import static android.net.RouteInfo.RTN_THROW; import static android.net.RouteInfo.RTN_UNICAST; import static android.net.RouteInfo.RTN_UNREACHABLE; -import static com.android.testutils.ParcelUtilsKt.assertParcelSane; -import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless; -import static com.android.testutils.ParcelUtilsKt.parcelingRoundTrip; +import static com.android.testutils.ParcelUtils.assertParcelSane; +import static com.android.testutils.ParcelUtils.assertParcelingIsLossless; +import static com.android.testutils.ParcelUtils.parcelingRoundTrip; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java index 3f8261d5ad7f..e1693129892f 100644 --- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java +++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java @@ -42,8 +42,8 @@ import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE; import static android.net.NetworkCapabilities.UNRESTRICTED_CAPABILITIES; -import static com.android.testutils.ParcelUtilsKt.assertParcelSane; -import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless; +import static com.android.testutils.ParcelUtils.assertParcelSane; +import static com.android.testutils.ParcelUtils.assertParcelingIsLossless; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; diff --git a/tests/net/common/java/android/net/RouteInfoTest.java b/tests/net/common/java/android/net/RouteInfoTest.java index 60cac0b6b0f5..71689f919726 100644 --- a/tests/net/common/java/android/net/RouteInfoTest.java +++ b/tests/net/common/java/android/net/RouteInfoTest.java @@ -18,10 +18,10 @@ package android.net; import static android.net.RouteInfo.RTN_UNREACHABLE; -import static com.android.testutils.MiscAssertsKt.assertEqualBothWays; -import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals; -import static com.android.testutils.MiscAssertsKt.assertNotEqualEitherWay; -import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless; +import static com.android.testutils.MiscAsserts.assertEqualBothWays; +import static com.android.testutils.MiscAsserts.assertFieldCountEquals; +import static com.android.testutils.MiscAsserts.assertNotEqualEitherWay; +import static com.android.testutils.ParcelUtils.assertParcelingIsLossless; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; diff --git a/tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java b/tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java index 84805442e5c7..d50406fd3a1c 100644 --- a/tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java +++ b/tests/net/common/java/android/net/apf/ApfCapabilitiesTest.java @@ -16,7 +16,7 @@ package android.net.apf; -import static com.android.testutils.ParcelUtilsKt.assertParcelSane; +import static com.android.testutils.ParcelUtils.assertParcelSane; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; diff --git a/tests/net/integration/util/com/android/server/ConnectivityServiceTestUtils.kt b/tests/net/integration/util/com/android/server/ConnectivityServiceTestUtils.kt index fa2b99ce5cc6..165fd3728281 100644 --- a/tests/net/integration/util/com/android/server/ConnectivityServiceTestUtils.kt +++ b/tests/net/integration/util/com/android/server/ConnectivityServiceTestUtils.kt @@ -14,6 +14,8 @@ * limitations under the License */ +@file:JvmName("ConnectivityServiceTestUtils") + package com.android.server import android.net.ConnectivityManager.TYPE_BLUETOOTH diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java index 0ffafd45613a..9f0b41fa0cdf 100644 --- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java +++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java @@ -24,7 +24,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE; -import static com.android.server.ConnectivityServiceTestUtilsKt.transportToLegacyType; +import static com.android.server.ConnectivityServiceTestUtils.transportToLegacyType; import static junit.framework.Assert.assertTrue; @@ -49,7 +49,7 @@ import android.os.Message; import android.util.Log; import com.android.server.connectivity.ConnectivityConstants; -import com.android.testutils.HandlerUtilsKt; +import com.android.testutils.HandlerUtils; import com.android.testutils.TestableNetworkCallback; import java.util.Set; @@ -265,6 +265,6 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork { } public void waitForIdle(long timeoutMs) { - HandlerUtilsKt.waitForIdle(mHandlerThread, timeoutMs); + HandlerUtils.waitForIdle(mHandlerThread, timeoutMs); } } diff --git a/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java b/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java index 1d6c10766792..06e9405a6a79 100644 --- a/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java +++ b/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java @@ -21,7 +21,7 @@ import static android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnostics import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport; import static android.net.ConnectivityDiagnosticsManager.DataStallReport; -import static com.android.testutils.ParcelUtilsKt.assertParcelSane; +import static com.android.testutils.ParcelUtils.assertParcelSane; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; diff --git a/tests/net/java/android/net/IpSecConfigTest.java b/tests/net/java/android/net/IpSecConfigTest.java index c9888b24b6da..25e225ef303a 100644 --- a/tests/net/java/android/net/IpSecConfigTest.java +++ b/tests/net/java/android/net/IpSecConfigTest.java @@ -16,8 +16,8 @@ package android.net; -import static com.android.testutils.ParcelUtilsKt.assertParcelSane; -import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless; +import static com.android.testutils.ParcelUtils.assertParcelSane; +import static com.android.testutils.ParcelUtils.assertParcelingIsLossless; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotSame; diff --git a/tests/net/java/android/net/TcpKeepalivePacketDataTest.java b/tests/net/java/android/net/TcpKeepalivePacketDataTest.java index cea8c5713a6b..835a83e9ddc7 100644 --- a/tests/net/java/android/net/TcpKeepalivePacketDataTest.java +++ b/tests/net/java/android/net/TcpKeepalivePacketDataTest.java @@ -16,7 +16,7 @@ package android.net; -import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless; +import static com.android.testutils.ParcelUtils.assertParcelingIsLossless; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; diff --git a/tests/net/java/android/net/TelephonyNetworkSpecifierTest.java b/tests/net/java/android/net/TelephonyNetworkSpecifierTest.java index efb92033df1e..6714bb1abbe6 100644 --- a/tests/net/java/android/net/TelephonyNetworkSpecifierTest.java +++ b/tests/net/java/android/net/TelephonyNetworkSpecifierTest.java @@ -16,7 +16,7 @@ package android.net; -import static com.android.testutils.ParcelUtilsKt.assertParcelSane; +import static com.android.testutils.ParcelUtils.assertParcelSane; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; diff --git a/tests/net/java/android/net/nsd/NsdManagerTest.java b/tests/net/java/android/net/nsd/NsdManagerTest.java index cf7587a2039f..b0a9b8a55322 100644 --- a/tests/net/java/android/net/nsd/NsdManagerTest.java +++ b/tests/net/java/android/net/nsd/NsdManagerTest.java @@ -38,7 +38,7 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.AsyncChannel; -import com.android.testutils.HandlerUtilsKt; +import com.android.testutils.HandlerUtils; import org.junit.After; import org.junit.Before; @@ -73,7 +73,7 @@ public class NsdManagerTest { @After public void tearDown() throws Exception { - HandlerUtilsKt.waitForIdle(mServiceHandler, mTimeoutMs); + HandlerUtils.waitForIdle(mServiceHandler, mTimeoutMs); mServiceHandler.chan.disconnect(); mServiceHandler.stop(); if (mManager != null) { @@ -333,7 +333,7 @@ public class NsdManagerTest { } int verifyRequest(int expectedMessageType) { - HandlerUtilsKt.waitForIdle(mServiceHandler, mTimeoutMs); + HandlerUtils.waitForIdle(mServiceHandler, mTimeoutMs); verify(mServiceHandler, timeout(mTimeoutMs)).handleMessage(any()); reset(mServiceHandler); Message received = mServiceHandler.getLastMessage(); diff --git a/tests/net/java/com/android/internal/net/VpnProfileTest.java b/tests/net/java/com/android/internal/net/VpnProfileTest.java index e5daa71c30ea..46597d19ef1b 100644 --- a/tests/net/java/com/android/internal/net/VpnProfileTest.java +++ b/tests/net/java/com/android/internal/net/VpnProfileTest.java @@ -16,7 +16,7 @@ package com.android.internal.net; -import static com.android.testutils.ParcelUtilsKt.assertParcelSane; +import static com.android.testutils.ParcelUtils.assertParcelSane; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 0f24b0c1c79b..a3673df1c713 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -78,16 +78,16 @@ import static android.net.RouteInfo.RTN_UNREACHABLE; import static android.os.Process.INVALID_UID; import static android.system.OsConstants.IPPROTO_TCP; -import static com.android.server.ConnectivityServiceTestUtilsKt.transportToLegacyType; -import static com.android.testutils.ConcurrentUtilsKt.await; -import static com.android.testutils.ConcurrentUtilsKt.durationOf; +import static com.android.server.ConnectivityServiceTestUtils.transportToLegacyType; +import static com.android.testutils.ConcurrentUtils.await; +import static com.android.testutils.ConcurrentUtils.durationOf; import static com.android.testutils.ExceptionUtils.ignoreExceptions; -import static com.android.testutils.HandlerUtilsKt.waitForIdleSerialExecutor; -import static com.android.testutils.MiscAssertsKt.assertContainsExactly; -import static com.android.testutils.MiscAssertsKt.assertEmpty; -import static com.android.testutils.MiscAssertsKt.assertLength; -import static com.android.testutils.MiscAssertsKt.assertRunsInAtMost; -import static com.android.testutils.MiscAssertsKt.assertThrows; +import static com.android.testutils.HandlerUtils.waitForIdleSerialExecutor; +import static com.android.testutils.MiscAsserts.assertContainsExactly; +import static com.android.testutils.MiscAsserts.assertEmpty; +import static com.android.testutils.MiscAsserts.assertLength; +import static com.android.testutils.MiscAsserts.assertRunsInAtMost; +import static com.android.testutils.MiscAsserts.assertThrows; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -242,7 +242,7 @@ import com.android.server.connectivity.Vpn; import com.android.server.net.NetworkPinner; import com.android.server.net.NetworkPolicyManagerInternal; import com.android.testutils.ExceptionUtils; -import com.android.testutils.HandlerUtilsKt; +import com.android.testutils.HandlerUtils; import com.android.testutils.RecorderCallback.CallbackEntry; import com.android.testutils.TestableNetworkCallback; @@ -518,12 +518,12 @@ public class ConnectivityServiceTest { } private void waitForIdle() { - HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS); + HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS); waitForIdle(mCellNetworkAgent, TIMEOUT_MS); waitForIdle(mWiFiNetworkAgent, TIMEOUT_MS); waitForIdle(mEthernetNetworkAgent, TIMEOUT_MS); - HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS); - HandlerUtilsKt.waitForIdle(ConnectivityThread.get(), TIMEOUT_MS); + HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS); + HandlerUtils.waitForIdle(ConnectivityThread.get(), TIMEOUT_MS); } private void waitForIdle(TestNetworkAgentWrapper agent, long timeoutMs) { @@ -614,8 +614,8 @@ public class ConnectivityServiceTest { // Waits for the NetworkAgent to be registered, which includes the creation of the // NetworkMonitor. waitForIdle(TIMEOUT_MS); - HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS); - HandlerUtilsKt.waitForIdle(ConnectivityThread.get(), TIMEOUT_MS); + HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS); + HandlerUtils.waitForIdle(ConnectivityThread.get(), TIMEOUT_MS); } @Override @@ -7099,7 +7099,7 @@ public class ConnectivityServiceTest { mConnectivityDiagnosticsCallback, wifiRequest, mContext.getPackageName()); // Block until all other events are done processing. - HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS); + HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS); verify(mIBinder).linkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt()); verify(mConnectivityDiagnosticsCallback).asBinder(); @@ -7122,7 +7122,7 @@ public class ConnectivityServiceTest { mConnectivityDiagnosticsCallback, wifiRequest, mContext.getPackageName()); // Block until all other events are done processing. - HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS); + HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS); verify(mIBinder).linkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt()); verify(mConnectivityDiagnosticsCallback).asBinder(); @@ -7133,7 +7133,7 @@ public class ConnectivityServiceTest { mConnectivityDiagnosticsCallback, wifiRequest, mContext.getPackageName()); // Block until all other events are done processing. - HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS); + HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS); assertTrue(mService.mConnectivityDiagnosticsCallbacks.containsKey(mIBinder)); } @@ -7285,7 +7285,7 @@ public class ConnectivityServiceTest { mConnectivityDiagnosticsCallback, request, mContext.getPackageName()); // Block until all other events are done processing. - HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS); + HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS); verify(mConnectivityDiagnosticsCallback) .onConnectivityReportAvailable(argThat(report -> { @@ -7305,7 +7305,7 @@ public class ConnectivityServiceTest { mConnectivityDiagnosticsCallback, request, mContext.getPackageName()); // Block until all other events are done processing. - HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS); + HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS); // Connect the cell agent verify that it notifies TestNetworkCallback that it is available final TestNetworkCallback callback = new TestNetworkCallback(); @@ -7322,7 +7322,7 @@ public class ConnectivityServiceTest { setUpConnectivityDiagnosticsCallback(); // Block until all other events are done processing. - HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS); + HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS); // Verify onConnectivityReport fired verify(mConnectivityDiagnosticsCallback).onConnectivityReportAvailable( @@ -7343,7 +7343,7 @@ public class ConnectivityServiceTest { mCellNetworkAgent.notifyDataStallSuspected(); // Block until all other events are done processing. - HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS); + HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS); // Verify onDataStallSuspected fired verify(mConnectivityDiagnosticsCallback).onDataStallSuspected( @@ -7364,7 +7364,7 @@ public class ConnectivityServiceTest { mService.reportNetworkConnectivity(n, hasConnectivity); // Block until all other events are done processing. - HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS); + HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS); // Verify onNetworkConnectivityReported fired verify(mConnectivityDiagnosticsCallback) @@ -7374,7 +7374,7 @@ public class ConnectivityServiceTest { mService.reportNetworkConnectivity(n, noConnectivity); // Block until all other events are done processing. - HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS); + HandlerUtils.waitForIdle(mCsHandlerThread, TIMEOUT_MS); // Wait for onNetworkConnectivityReported to fire verify(mConnectivityDiagnosticsCallback) diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java index 508b5cd9cb19..753dbf80b449 100644 --- a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java +++ b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java @@ -26,9 +26,9 @@ import static android.provider.Settings.Global.PRIVATE_DNS_DEFAULT_MODE; import static android.provider.Settings.Global.PRIVATE_DNS_MODE; import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER; -import static com.android.testutils.MiscAssertsKt.assertContainsExactly; -import static com.android.testutils.MiscAssertsKt.assertContainsStringsExactly; -import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals; +import static com.android.testutils.MiscAsserts.assertContainsExactly; +import static com.android.testutils.MiscAsserts.assertContainsStringsExactly; +import static com.android.testutils.MiscAsserts.assertFieldCountEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; diff --git a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java index aef9386755d7..8ccea1aa3474 100644 --- a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java +++ b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java @@ -19,7 +19,7 @@ package com.android.server.connectivity; import static android.net.metrics.INetdEventListener.EVENT_GETADDRINFO; import static android.net.metrics.INetdEventListener.EVENT_GETHOSTBYNAME; -import static com.android.testutils.MiscAssertsKt.assertStringContains; +import static com.android.testutils.MiscAsserts.assertStringContains; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java index a384687e06f6..ab12ac0ef56e 100644 --- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java @@ -28,11 +28,17 @@ import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRODUCT; import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_VENDOR; import static android.content.pm.PackageManager.GET_PERMISSIONS; import static android.content.pm.PackageManager.MATCH_ANY_USER; +import static android.net.INetd.PERMISSION_INTERNET; +import static android.net.INetd.PERMISSION_NONE; +import static android.net.INetd.PERMISSION_SYSTEM; +import static android.net.INetd.PERMISSION_UNINSTALLED; +import static android.net.INetd.PERMISSION_UPDATE_DEVICE_STATS; import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK; import static android.os.Process.SYSTEM_UID; import static com.android.server.connectivity.PermissionMonitor.NETWORK; import static com.android.server.connectivity.PermissionMonitor.SYSTEM; +import static com.android.server.connectivity.PermissionMonitor.UidNetdPermissionInfo; import static junit.framework.Assert.fail; @@ -63,7 +69,7 @@ import android.net.UidRange; import android.os.Build; import android.os.UserHandle; import android.os.UserManager; -import android.util.SparseIntArray; +import android.util.SparseArray; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; @@ -312,7 +318,7 @@ public class PermissionMonitorTest { // Add hook to verify and track result of setPermission. doAnswer((InvocationOnMock invocation) -> { final Object[] args = invocation.getArguments(); - final Boolean isSystem = args[0].equals(INetd.PERMISSION_SYSTEM); + final Boolean isSystem = args[0].equals(PERMISSION_SYSTEM); for (final int uid : (int[]) args[1]) { // TODO: Currently, permission monitor will send duplicate commands for each uid // corresponding to each user. Need to fix that and uncomment below test. @@ -555,39 +561,40 @@ public class PermissionMonitorTest { // SYSTEM_UID1: SYSTEM_PACKAGE1 has internet permission and update device stats permission. // SYSTEM_UID2: SYSTEM_PACKAGE2 has only update device stats permission. - SparseIntArray netdPermissionsAppIds = new SparseIntArray(); - netdPermissionsAppIds.put(MOCK_UID1, INetd.PERMISSION_INTERNET); - netdPermissionsAppIds.put(MOCK_UID2, INetd.PERMISSION_NONE); - netdPermissionsAppIds.put(SYSTEM_UID1, INetd.PERMISSION_INTERNET - | INetd.PERMISSION_UPDATE_DEVICE_STATS); - netdPermissionsAppIds.put(SYSTEM_UID2, INetd.PERMISSION_UPDATE_DEVICE_STATS); + final SparseArray<UidNetdPermissionInfo> uidsPermInfo = new SparseArray<>(); + uidsPermInfo.put(MOCK_UID1, new UidNetdPermissionInfo(PERMISSION_INTERNET)); + uidsPermInfo.put(MOCK_UID2, new UidNetdPermissionInfo(PERMISSION_NONE)); + uidsPermInfo.put(SYSTEM_UID1, new UidNetdPermissionInfo( + PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS)); + uidsPermInfo.put(SYSTEM_UID2, new UidNetdPermissionInfo(PERMISSION_UPDATE_DEVICE_STATS)); // Send the permission information to netd, expect permission updated. - mPermissionMonitor.sendPackagePermissionsToNetd(netdPermissionsAppIds); + mPermissionMonitor.sendPackagePermissionsToNetd(uidsPermInfo); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, + mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET, new int[]{MOCK_UID1}); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{MOCK_UID2}); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET - | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{SYSTEM_UID1}); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UPDATE_DEVICE_STATS, + mNetdServiceMonitor.expectPermission(PERMISSION_NONE, new int[]{MOCK_UID2}); + mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET + | PERMISSION_UPDATE_DEVICE_STATS, new int[]{SYSTEM_UID1}); + mNetdServiceMonitor.expectPermission(PERMISSION_UPDATE_DEVICE_STATS, new int[]{SYSTEM_UID2}); // Update permission of MOCK_UID1, expect new permission show up. - mPermissionMonitor.sendPackagePermissionsForUid(MOCK_UID1, - INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET - | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); + mPermissionMonitor.sendPackagePermissionsForUid(MOCK_UID1, new UidNetdPermissionInfo( + PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS)); + mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET + | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); // Change permissions of SYSTEM_UID2, expect new permission show up and old permission // revoked. - mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID2, - INetd.PERMISSION_INTERNET); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{SYSTEM_UID2}); + mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID2, new UidNetdPermissionInfo( + PERMISSION_INTERNET)); + mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET, new int[]{SYSTEM_UID2}); // Revoke permission from SYSTEM_UID1, expect no permission stored. - mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID1, INetd.PERMISSION_NONE); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{SYSTEM_UID1}); + mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID1, new UidNetdPermissionInfo( + PERMISSION_NONE)); + mNetdServiceMonitor.expectPermission(PERMISSION_NONE, new int[]{SYSTEM_UID1}); } private PackageInfo setPackagePermissions(String packageName, int uid, String[] permissions) @@ -611,11 +618,11 @@ public class PermissionMonitorTest { final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService); addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS}); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET - | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); + mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET + | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); addPackage(MOCK_PACKAGE2, MOCK_UID2, new String[] {INTERNET}); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID2}); + mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET, new int[]{MOCK_UID2}); } @Test @@ -623,8 +630,8 @@ public class PermissionMonitorTest { final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService); addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS}); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET - | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); + mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET + | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); // Install another package with the same uid and no permissions should not cause the UID to // lose permissions. @@ -633,8 +640,8 @@ public class PermissionMonitorTest { when(mPackageManager.getPackagesForUid(MOCK_UID1)) .thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2}); mPermissionMonitor.onPackageAdded(MOCK_PACKAGE2, MOCK_UID1); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET - | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); + mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET + | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); } @Test @@ -642,12 +649,12 @@ public class PermissionMonitorTest { final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService); addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS}); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET - | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); + mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET + | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{}); mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1}); + mNetdServiceMonitor.expectPermission(PERMISSION_UNINSTALLED, new int[]{MOCK_UID1}); } @Test @@ -655,16 +662,16 @@ public class PermissionMonitorTest { final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService); addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS}); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET - | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); + mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET + | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{}); removeAllPermissions(MOCK_UID1); mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1}); + mNetdServiceMonitor.expectPermission(PERMISSION_UNINSTALLED, new int[]{MOCK_UID1}); addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET}); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1}); + mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET, new int[]{MOCK_UID1}); } @Test @@ -672,10 +679,10 @@ public class PermissionMonitorTest { final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService); addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {}); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{MOCK_UID1}); + mNetdServiceMonitor.expectPermission(PERMISSION_NONE, new int[]{MOCK_UID1}); addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET}); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1}); + mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET, new int[]{MOCK_UID1}); } @Test @@ -683,8 +690,8 @@ public class PermissionMonitorTest { final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService); addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS}); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET - | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); + mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET + | PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); // Mock another package with the same uid but different permissions. final PackageInfo packageInfo2 = buildPackageInfo(PARTITION_SYSTEM, MOCK_UID1, MOCK_USER1); @@ -695,7 +702,7 @@ public class PermissionMonitorTest { addPermissions(MOCK_UID1, INTERNET); mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1); - mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1}); + mNetdServiceMonitor.expectPermission(PERMISSION_INTERNET, new int[]{MOCK_UID1}); } @Test diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index de1c5759ee87..e8c4ee9c628d 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -270,12 +270,12 @@ public class VpnTest { } @Test - public void testUidWhiteAndBlacklist() throws Exception { + public void testUidAllowAndDenylist() throws Exception { final Vpn vpn = createVpn(primaryUser.id); final UidRange user = UidRange.createForUser(primaryUser.id); final String[] packages = {PKGS[0], PKGS[1], PKGS[2]}; - // Whitelist + // Allowed list final Set<UidRange> allow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, Arrays.asList(packages), null); assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { @@ -283,7 +283,7 @@ public class VpnTest { new UidRange(user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]) })), allow); - // Blacklist + // Denied list final Set<UidRange> disallow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, null, Arrays.asList(packages)); assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { @@ -354,11 +354,11 @@ public class VpnTest { } @Test - public void testLockdownWhitelist() throws Exception { + public void testLockdownAllowlist() throws Exception { final Vpn vpn = createVpn(primaryUser.id); final UidRange user = UidRange.createForUser(primaryUser.id); - // Set always-on with lockdown and whitelist app PKGS[2] from lockdown. + // Set always-on with lockdown and allow app PKGS[2] from lockdown. assertTrue(vpn.setAlwaysOnPackage( PKGS[1], true, Collections.singletonList(PKGS[2]), mKeyStore)); verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] { @@ -368,7 +368,7 @@ public class VpnTest { assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]); assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]); - // Change whitelisted app to PKGS[3]. + // Change allowed app list to PKGS[3]. assertTrue(vpn.setAlwaysOnPackage( PKGS[1], true, Collections.singletonList(PKGS[3]), mKeyStore)); verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] { @@ -395,7 +395,7 @@ public class VpnTest { assertBlocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]); assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]); - // Remove the whitelist. + // Remove the list of allowed packages. assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null, mKeyStore)); verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] { new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1), @@ -408,7 +408,7 @@ public class VpnTest { user.start + PKG_UIDS[3]); assertUnblocked(vpn, user.start + PKG_UIDS[0]); - // Add the whitelist. + // Add the list of allowed packages. assertTrue(vpn.setAlwaysOnPackage( PKGS[0], true, Collections.singletonList(PKGS[1]), mKeyStore)); verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] { @@ -421,12 +421,12 @@ public class VpnTest { assertBlocked(vpn, user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]); assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1]); - // Try whitelisting a package with a comma, should be rejected. + // Try allowing a package with a comma, should be rejected. assertFalse(vpn.setAlwaysOnPackage( PKGS[0], true, Collections.singletonList("a.b,c.d"), mKeyStore)); - // Pass a non-existent packages in the whitelist, they (and only they) should be ignored. - // Whitelisted package should change from PGKS[1] to PKGS[2]. + // Pass a non-existent packages in the allowlist, they (and only they) should be ignored. + // allowed package should change from PGKS[1] to PKGS[2]. assertTrue(vpn.setAlwaysOnPackage( PKGS[0], true, Arrays.asList("com.foo.app", PKGS[2], "com.bar.app"), mKeyStore)); verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[]{ diff --git a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java index e83d2a90bffa..fb0cfc0d50ba 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java @@ -28,7 +28,7 @@ import static android.os.Process.myUid; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; -import static com.android.testutils.MiscAssertsKt.assertThrows; +import static com.android.testutils.MiscAsserts.assertThrows; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; diff --git a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java index a6f7a36ff01b..291efc74aa47 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java @@ -53,7 +53,7 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.server.net.NetworkStatsServiceTest.LatchedHandler; -import com.android.testutils.HandlerUtilsKt; +import com.android.testutils.HandlerUtils; import org.junit.Before; import org.junit.Test; @@ -440,7 +440,7 @@ public class NetworkStatsObserversTest { } private void waitForObserverToIdle() { - HandlerUtilsKt.waitForIdle(mObserverHandlerThread, WAIT_TIMEOUT_MS); - HandlerUtilsKt.waitForIdle(mHandler, WAIT_TIMEOUT_MS); + HandlerUtils.waitForIdle(mObserverHandlerThread, WAIT_TIMEOUT_MS); + HandlerUtils.waitForIdle(mHandler, WAIT_TIMEOUT_MS); } } diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java index 1307a849f1eb..7abe1893dd9e 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java @@ -109,7 +109,7 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.server.net.NetworkStatsService.NetworkStatsSettings; import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config; -import com.android.testutils.HandlerUtilsKt; +import com.android.testutils.HandlerUtils; import com.android.testutils.TestableNetworkStatsProviderBinder; import libcore.io.IoUtils; @@ -700,7 +700,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { when(mNetworkStatsSubscriptionsMonitor.getRatTypeForSubscriberId(anyString())) .thenReturn(ratType); mService.handleOnCollapsedRatTypeChanged(); - HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT); + HandlerUtils.waitForIdle(mHandlerThread, WAIT_TIMEOUT); } @Test @@ -1065,7 +1065,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { long minThresholdInBytes = 2 * 1024 * 1024; // 2 MB assertEquals(minThresholdInBytes, request.thresholdInBytes); - HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT); + HandlerUtils.waitForIdle(mHandlerThread, WAIT_TIMEOUT); // Make sure that the caller binder gets connected verify(mBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt()); @@ -1203,7 +1203,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { // Simulates alert quota of the provider has been reached. cb.notifyAlertReached(); - HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT); + HandlerUtils.waitForIdle(mHandlerThread, WAIT_TIMEOUT); // Verifies that polling is triggered by alert reached. provider.expectOnRequestStatsUpdate(0 /* unused */); @@ -1264,7 +1264,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { // Call handleOnCollapsedRatTypeChanged manually to simulate the callback fired // when stopping monitor, this is needed by NetworkStatsService to trigger updateIfaces. mService.handleOnCollapsedRatTypeChanged(); - HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT); + HandlerUtils.waitForIdle(mHandlerThread, WAIT_TIMEOUT); // Create some traffic. incrementCurrentTime(MINUTE_IN_MILLIS); // Append more traffic on existing snapshot. @@ -1286,7 +1286,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { setCombineSubtypeEnabled(false); mService.handleOnCollapsedRatTypeChanged(); - HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT); + HandlerUtils.waitForIdle(mHandlerThread, WAIT_TIMEOUT); // Create some traffic. incrementCurrentTime(MINUTE_IN_MILLIS); // Append more traffic on existing snapshot. @@ -1520,7 +1520,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { } private void waitForIdle() { - HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT); + HandlerUtils.waitForIdle(mHandlerThread, WAIT_TIMEOUT); } static class LatchedHandler extends Handler { diff --git a/tools/hiddenapi/generate_hiddenapi_lists.py b/tools/hiddenapi/generate_hiddenapi_lists.py index 8a282e5f0821..da644021e30e 100755 --- a/tools/hiddenapi/generate_hiddenapi_lists.py +++ b/tools/hiddenapi/generate_hiddenapi_lists.py @@ -34,26 +34,6 @@ FLAG_PUBLIC_API = 'public-api' FLAG_SYSTEM_API = 'system-api' FLAG_TEST_API = 'test-api' -OLD_FLAG_SDK = "whitelist" -OLD_FLAG_UNSUPPORTED = "greylist" -OLD_FLAG_BLOCKED = "blacklist" -OLD_FLAG_MAX_TARGET_O = "greylist-max-o" -OLD_FLAG_MAX_TARGET_P = "greylist-max-p" -OLD_FLAG_MAX_TARGET_Q = "greylist-max-q" -OLD_FLAG_MAX_TARGET_R = "greylist-max-r" - -OLD_FLAGS_TO_NEW = { - OLD_FLAG_SDK: FLAG_SDK, - OLD_FLAG_UNSUPPORTED: FLAG_UNSUPPORTED, - OLD_FLAG_BLOCKED: FLAG_BLOCKED, - OLD_FLAG_MAX_TARGET_O: FLAG_MAX_TARGET_O, - OLD_FLAG_MAX_TARGET_P: FLAG_MAX_TARGET_P, - OLD_FLAG_MAX_TARGET_Q: FLAG_MAX_TARGET_Q, - OLD_FLAG_MAX_TARGET_R: FLAG_MAX_TARGET_R, -} - -NEW_FLAGS_TO_OLD = dict(zip(OLD_FLAGS_TO_NEW.values(), OLD_FLAGS_TO_NEW.keys())) - # List of all known flags. FLAGS_API_LIST = [ FLAG_SDK, @@ -205,36 +185,6 @@ class FlagsDict: "Please visit go/hiddenapi for more information.").format( source, "\n".join(flags_subset - ALL_FLAGS_SET)) - def convert_to_new_flag(self, flag): - """Converts old flag to a new variant. - - Flags that are considered old are replaced with new versions. - Otherwise, it is a no-op. - - Args: - flag: a string, representing SDK flag. - - Returns: - A string. Result of conversion. - - """ - return OLD_FLAGS_TO_NEW.get(flag, flag) - - def convert_to_old_flag(self, flag): - """Converts a new flag to a old variant. - - No-op if there is no suitable old flag. - Only used to support backwards compatibility. - - Args: - flag: a string, representing SDK flag. - - Returns: - A string. Result of conversion. - - """ - return NEW_FLAGS_TO_OLD.get(flag, flag) - def filter_apis(self, filter_fn): """Returns APIs which match a given predicate. @@ -272,7 +222,7 @@ class FlagsDict: """ lines = [] for api in self._dict: - flags = sorted([self.convert_to_old_flag(flag) for flag in self._dict[api]]) + flags = sorted(self._dict[api]) lines.append(",".join([api] + flags)) return sorted(lines) @@ -298,12 +248,12 @@ class FlagsDict: # Check that all flags are known. csv_flags = set() for csv in csv_values: - csv_flags.update([self.convert_to_new_flag(flag) for flag in csv[1:]]) + csv_flags.update(csv[1:]) self._check_flags_set(csv_flags, source) # Iterate over all CSV lines, find entry in dict and append flags to it. for csv in csv_values: - flags = [self.convert_to_new_flag(flag) for flag in csv[1:]] + flags = csv[1:] if (FLAG_PUBLIC_API in flags) or (FLAG_SYSTEM_API in flags): flags.append(FLAG_SDK) self._dict[csv[0]].update(flags) diff --git a/tools/hiddenapi/generate_hiddenapi_lists_test.py b/tools/hiddenapi/generate_hiddenapi_lists_test.py index 321c400ef898..82d117fbbbab 100755 --- a/tools/hiddenapi/generate_hiddenapi_lists_test.py +++ b/tools/hiddenapi/generate_hiddenapi_lists_test.py @@ -35,7 +35,7 @@ class TestHiddenapiListGeneration(unittest.TestCase): flags.parse_and_merge_csv(['A,' + FLAG_SDK, 'B', 'C']) flags.assign_flag(FLAG_UNSUPPORTED, set(['C'])) self.assertEqual(flags.generate_csv(), - [ 'A,' + OLD_FLAG_SDK, 'B', 'C,' + OLD_FLAG_UNSUPPORTED ]) + [ 'A,' + FLAG_SDK, 'B', 'C,' + FLAG_UNSUPPORTED ]) # Check three things: # (1) B is selected as valid unassigned @@ -50,8 +50,7 @@ class TestHiddenapiListGeneration(unittest.TestCase): # Test empty CSV entry. self.assertEqual(flags.generate_csv(), []) - # Test new additions. CSV generator produces values with old flags - # to be backwards compatible. + # Test new additions. flags.parse_and_merge_csv([ 'A,' + FLAG_UNSUPPORTED, 'B,' + FLAG_BLOCKED + ',' + FLAG_MAX_TARGET_O, @@ -60,11 +59,11 @@ class TestHiddenapiListGeneration(unittest.TestCase): 'E,' + FLAG_BLOCKED + ',' + FLAG_TEST_API, ]) self.assertEqual(flags.generate_csv(), [ - 'A,' + OLD_FLAG_UNSUPPORTED, - 'B,' + OLD_FLAG_BLOCKED + "," + OLD_FLAG_MAX_TARGET_O, - 'C,' + FLAG_SYSTEM_API + ',' + OLD_FLAG_SDK, - 'D,' + OLD_FLAG_UNSUPPORTED + ',' + FLAG_TEST_API, - 'E,' + OLD_FLAG_BLOCKED + ',' + FLAG_TEST_API, + 'A,' + FLAG_UNSUPPORTED, + 'B,' + FLAG_BLOCKED + "," + FLAG_MAX_TARGET_O, + 'C,' + FLAG_SYSTEM_API + ',' + FLAG_SDK, + 'D,' + FLAG_UNSUPPORTED + ',' + FLAG_TEST_API, + 'E,' + FLAG_BLOCKED + ',' + FLAG_TEST_API, ]) # Test unknown flag. @@ -78,7 +77,7 @@ class TestHiddenapiListGeneration(unittest.TestCase): # Test new additions. flags.assign_flag(FLAG_UNSUPPORTED, set([ 'A', 'B' ])) self.assertEqual(flags.generate_csv(), - [ 'A,' + OLD_FLAG_UNSUPPORTED + "," + OLD_FLAG_SDK, 'B,' + OLD_FLAG_UNSUPPORTED ]) + [ 'A,' + FLAG_UNSUPPORTED + "," + FLAG_SDK, 'B,' + FLAG_UNSUPPORTED ]) # Test invalid API signature. with self.assertRaises(AssertionError): diff --git a/wifi/java/android/net/wifi/SoftApConfiguration.java b/wifi/java/android/net/wifi/SoftApConfiguration.java index f919ea4c4797..393fe8d3ab9a 100644 --- a/wifi/java/android/net/wifi/SoftApConfiguration.java +++ b/wifi/java/android/net/wifi/SoftApConfiguration.java @@ -582,6 +582,7 @@ public final class SoftApConfiguration implements Parcelable { wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); break; case SECURITY_TYPE_WPA2_PSK: + case SECURITY_TYPE_WPA3_SAE_TRANSITION: wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA2_PSK); break; default: diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java index fa806e7797cd..282757ac5a14 100644 --- a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java +++ b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java @@ -448,6 +448,16 @@ public final class Credential implements Parcelable { return new UserCredential[size]; } }; + + /** + * Get a unique identifier for UserCredential. + * + * @hide + * @return a Unique identifier for a UserCredential object + */ + public int getUniqueId() { + return Objects.hash(mUsername); + } } private UserCredential mUserCredential = null; /** @@ -1037,7 +1047,8 @@ public final class Credential implements Parcelable { * @return a Unique identifier for a Credential object */ public int getUniqueId() { - return Objects.hash(mUserCredential, mCertCredential, mSimCredential, mRealm); + return Objects.hash(mUserCredential != null ? mUserCredential.getUniqueId() : 0, + mCertCredential, mSimCredential, mRealm); } @Override diff --git a/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java index 224c4bed9d5b..8f34579f6a5d 100644 --- a/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java +++ b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java @@ -313,9 +313,7 @@ public final class HomeSp implements Parcelable { * @return a Unique identifier for a HomeSp object */ public int getUniqueId() { - return Objects.hash(mFqdn, mFriendlyName, mHomeNetworkIds, Arrays.hashCode(mMatchAllOis), - Arrays.hashCode(mMatchAnyOis), Arrays.hashCode(mOtherHomePartners), - Arrays.hashCode(mRoamingConsortiumOis)); + return Objects.hash(mFqdn); } diff --git a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl index bfdd45d9f9b0..fd89d3b0486e 100644 --- a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl +++ b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl @@ -25,7 +25,7 @@ import android.os.Messenger; */ interface IWifiP2pManager { - Messenger getMessenger(in IBinder binder); + Messenger getMessenger(in IBinder binder, in String packageName); Messenger getP2pStateMachineMessenger(); oneway void close(in IBinder binder); void setMiracastMode(int mode); diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java index 724ccf0d7c45..ad38c5af07fc 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java @@ -1156,8 +1156,8 @@ public class WifiP2pManager { */ public Channel initialize(Context srcContext, Looper srcLooper, ChannelListener listener) { Binder binder = new Binder(); - Channel channel = initalizeChannel(srcContext, srcLooper, listener, getMessenger(binder), - binder); + Channel channel = initializeChannel(srcContext, srcLooper, listener, + getMessenger(binder, srcContext.getOpPackageName()), binder); return channel; } @@ -1167,12 +1167,12 @@ public class WifiP2pManager { */ public Channel initializeInternal(Context srcContext, Looper srcLooper, ChannelListener listener) { - return initalizeChannel(srcContext, srcLooper, listener, getP2pStateMachineMessenger(), + return initializeChannel(srcContext, srcLooper, listener, getP2pStateMachineMessenger(), null); } - private Channel initalizeChannel(Context srcContext, Looper srcLooper, ChannelListener listener, - Messenger messenger, Binder binder) { + private Channel initializeChannel(Context srcContext, Looper srcLooper, + ChannelListener listener, Messenger messenger, Binder binder) { if (messenger == null) return null; Channel c = new Channel(srcContext, srcLooper, listener, binder, this); @@ -1814,6 +1814,14 @@ public class WifiP2pManager { } } + private Messenger getMessenger(@NonNull Binder binder, @Nullable String packageName) { + try { + return mService.getMessenger(binder, packageName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Get a reference to WifiP2pService handler. This is used to establish * an AsyncChannel communication with WifiService @@ -1824,11 +1832,8 @@ public class WifiP2pManager { * @hide */ public Messenger getMessenger(Binder binder) { - try { - return mService.getMessenger(binder); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + // No way to determine package name in this case. + return getMessenger(binder, null); } /** diff --git a/wifi/tests/src/android/net/wifi/FakeKeys.java b/wifi/tests/src/android/net/wifi/FakeKeys.java index c0d60c33f99c..641b891a1f4d 100644 --- a/wifi/tests/src/android/net/wifi/FakeKeys.java +++ b/wifi/tests/src/android/net/wifi/FakeKeys.java @@ -214,6 +214,35 @@ public class FakeKeys { }; public static final PrivateKey RSA_KEY1 = loadPrivateRSAKey(FAKE_RSA_KEY_1); + private static final String CLIENT_SUITE_B_RSA3072_CERT_STRING = + "-----BEGIN CERTIFICATE-----\n" + + "MIIERzCCAq8CFDopjyNgaj+c2TN2k06h7okEWpHJMA0GCSqGSIb3DQEBDAUAMF4x\n" + + "CzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEMMAoGA1UEBwwDTVRWMRAwDgYDVQQK\n" + + "DAdBbmRyb2lkMQ4wDAYDVQQLDAVXaS1GaTESMBAGA1UEAwwJdW5pdGVzdENBMB4X\n" + + "DTIwMDcyMTAyMjkxMVoXDTMwMDUzMDAyMjkxMVowYjELMAkGA1UEBhMCVVMxCzAJ\n" + + "BgNVBAgMAkNBMQwwCgYDVQQHDANNVFYxEDAOBgNVBAoMB0FuZHJvaWQxDjAMBgNV\n" + + "BAsMBVdpLUZpMRYwFAYDVQQDDA11bml0ZXN0Q2xpZW50MIIBojANBgkqhkiG9w0B\n" + + "AQEFAAOCAY8AMIIBigKCAYEAwSK3C5K5udtCKTnE14e8z2cZvwmB4Xe+a8+7QLud\n" + + "Hooc/lQzClgK4MbVUC0D3FE+U32C78SxKoTaRWtvPmNm+UaFT8KkwyUno/dv+2XD\n" + + "pd/zARQ+3FwAfWopAhEyCVSxwsCa+slQ4juRIMIuUC1Mm0NaptZyM3Tj/ICQEfpk\n" + + "o9qVIbiK6eoJMTkY8EWfAn7RTFdfR1OLuO0mVOjgLW9/+upYv6hZ19nAMAxw4QTJ\n" + + "x7lLwALX7B+tDYNEZHDqYL2zyvQWAj2HClere8QYILxkvktgBg2crEJJe4XbDH7L\n" + + "A3rrXmsiqf1ZbfFFEzK9NFqovL+qGh+zIP+588ShJFO9H/RDnDpiTnAFTWXQdTwg\n" + + "szSS0Vw2PB+JqEABAa9DeMvXT1Oy+NY3ItPHyy63nQZVI2rXANw4NhwS0Z6DF+Qs\n" + + "TNrj+GU7e4SG/EGR8SvldjYfQTWFLg1l/UT1hOOkQZwdsaW1zgKyeuiFB2KdMmbA\n" + + "Sq+Ux1L1KICo0IglwWcB/8nnAgMBAAEwDQYJKoZIhvcNAQEMBQADggGBAMYwJkNw\n" + + "BaCviKFmReDTMwWPRy4AMNViEeqAXgERwDEKwM7efjsaj5gctWfKsxX6UdLzkhgg\n" + + "6S/T6PxVWKzJ6l7SoOuTa6tMQOZp+h3R1mdfEQbw8B5cXBxZ+batzAai6Fiy1FKS\n" + + "/ka3INbcGfYuIYghfTrb4/NJKN06ZaQ1bpPwq0e4gN7800T2nbawvSf7r+8ZLcG3\n" + + "6bGCjRMwDSIipNvOwoj3TG315XC7TccX5difQ4sKOY+d2MkVJ3RiO0Ciw2ZbEW8d\n" + + "1FH5vUQJWnBUfSFznosGzLwH3iWfqlP+27jNE+qB2igEwCRFgVAouURx5ou43xuX\n" + + "qf6JkdI3HTJGLIWxkp7gOeln4dEaYzKjYw+P0VqJvKVqQ0IXiLjHgE0J9p0vgyD6\n" + + "HVVcP7U8RgqrbIjL1QgHU4KBhGi+WSUh/mRplUCNvHgcYdcHi/gHpj/j6ubwqIGV\n" + + "z4iSolAHYTmBWcLyE0NgpzE6ntp+53r2KaUJA99l2iGVzbWTwqPSm0XAVw==\n" + + "-----END CERTIFICATE-----\n"; + public static final X509Certificate CLIENT_SUITE_B_RSA3072_CERT = + loadCertificate(CLIENT_SUITE_B_RSA3072_CERT_STRING); + private static X509Certificate loadCertificate(String blob) { try { final CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); diff --git a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java index c2d0d6d81e84..254434b81f8f 100644 --- a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java +++ b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java @@ -310,12 +310,6 @@ public class SoftApConfigurationTest { .build(); assertNull(band_6g_config.toWifiConfiguration()); - SoftApConfiguration sae_transition_config = new SoftApConfiguration.Builder() - .setPassphrase("secretsecret", - SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION) - .build(); - - assertNull(sae_transition_config.toWifiConfiguration()); } @Test @@ -358,5 +352,16 @@ public class SoftApConfigurationTest { assertThat(wifiConfig_2g5g.apBand).isEqualTo(WifiConfiguration.AP_BAND_ANY); assertThat(wifiConfig_2g5g.apChannel).isEqualTo(0); assertThat(wifiConfig_2g5g.hiddenSSID).isEqualTo(true); + + SoftApConfiguration softApConfig_sae_transition = new SoftApConfiguration.Builder() + .setPassphrase("secretsecret", + SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION) + .build(); + + WifiConfiguration wifiConfig_sae_transition = + softApConfig_sae_transition.toWifiConfiguration(); + assertThat(wifiConfig_sae_transition.getAuthType()) + .isEqualTo(WifiConfiguration.KeyMgmt.WPA2_PSK); + assertThat(wifiConfig_sae_transition.preSharedKey).isEqualTo("secretsecret"); } } diff --git a/wifi/tests/src/android/net/wifi/WifiClientTest.java b/wifi/tests/src/android/net/wifi/WifiClientTest.java index 42cab55305b9..7a3baf9ebaf2 100644 --- a/wifi/tests/src/android/net/wifi/WifiClientTest.java +++ b/wifi/tests/src/android/net/wifi/WifiClientTest.java @@ -16,8 +16,8 @@ package android.net.wifi; -import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals; -import static com.android.testutils.ParcelUtilsKt.assertParcelSane; +import static com.android.testutils.MiscAsserts.assertFieldCountEquals; +import static com.android.testutils.ParcelUtils.assertParcelSane; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java index 638efb9f14ee..8270d643ca65 100644 --- a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java +++ b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java @@ -23,6 +23,8 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; +import android.net.wifi.EAPConstants; +import android.net.wifi.FakeKeys; import android.net.wifi.hotspot2.pps.Credential; import android.net.wifi.hotspot2.pps.HomeSp; import android.os.Parcel; @@ -32,6 +34,11 @@ import androidx.test.filters.SmallTest; import org.junit.Test; import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -383,19 +390,39 @@ public class PasspointConfigurationTest { } /** - * Verify that the unique identifier generated is different for two instances with different - * HomeSp node + * Verify that the unique identifier generated is the same for two instances with different + * HomeSp node but same FQDN * * @throws Exception */ @Test - public void validateUniqueIdDifferentHomeSp() throws Exception { + public void validateUniqueIdDifferentHomeSpSameFqdn() throws Exception { PasspointConfiguration config1 = PasspointTestUtils.createConfig(); - // Modify config2's RCOIs to a different set of values + // Modify config2's RCOIs and friendly name to a different set of values PasspointConfiguration config2 = PasspointTestUtils.createConfig(); HomeSp homeSp = config2.getHomeSp(); homeSp.setRoamingConsortiumOis(new long[] {0xaa, 0xbb}); + homeSp.setFriendlyName("Some other name"); + config2.setHomeSp(homeSp); + + assertEquals(config1.getUniqueId(), config2.getUniqueId()); + } + + /** + * Verify that the unique identifier generated is different for two instances with the same + * HomeSp node but different FQDN + * + * @throws Exception + */ + @Test + public void validateUniqueIdSameHomeSpDifferentFqdn() throws Exception { + PasspointConfiguration config1 = PasspointTestUtils.createConfig(); + + // Modify config2's FQDN to a different value + PasspointConfiguration config2 = PasspointTestUtils.createConfig(); + HomeSp homeSp = config2.getHomeSp(); + homeSp.setFqdn("fqdn2.com"); config2.setHomeSp(homeSp); assertNotEquals(config1.getUniqueId(), config2.getUniqueId()); @@ -403,15 +430,15 @@ public class PasspointConfigurationTest { /** * Verify that the unique identifier generated is different for two instances with different - * Credential node + * SIM Credential node * * @throws Exception */ @Test - public void validateUniqueIdDifferentCredential() throws Exception { + public void validateUniqueIdDifferentSimCredential() throws Exception { PasspointConfiguration config1 = PasspointTestUtils.createConfig(); - // Modify config2's RCOIs to a different set of values + // Modify config2's realm and SIM credential to a different set of values PasspointConfiguration config2 = PasspointTestUtils.createConfig(); Credential credential = config2.getCredential(); credential.setRealm("realm2.example.com"); @@ -422,6 +449,157 @@ public class PasspointConfigurationTest { } /** + * Verify that the unique identifier generated is different for two instances with different + * Realm in the Credential node + * + * @throws Exception + */ + @Test + public void validateUniqueIdDifferentRealm() throws Exception { + PasspointConfiguration config1 = PasspointTestUtils.createConfig(); + + // Modify config2's realm to a different set of values + PasspointConfiguration config2 = PasspointTestUtils.createConfig(); + Credential credential = config2.getCredential(); + credential.setRealm("realm2.example.com"); + config2.setCredential(credential); + + assertNotEquals(config1.getUniqueId(), config2.getUniqueId()); + } + + /** + * Verify that the unique identifier generated is the same for two instances with different + * password and same username in the User Credential node + * + * @throws Exception + */ + @Test + public void validateUniqueIdSameUserInUserCredential() throws Exception { + PasspointConfiguration config1 = PasspointTestUtils.createConfig(); + Credential credential = createCredentialWithUserCredential("user", "passwd"); + config1.setCredential(credential); + + // Modify config2's Passpowrd to a different set of values + PasspointConfiguration config2 = PasspointTestUtils.createConfig(); + credential = createCredentialWithUserCredential("user", "newpasswd"); + config2.setCredential(credential); + + assertEquals(config1.getUniqueId(), config2.getUniqueId()); + } + + /** + * Verify that the unique identifier generated is different for two instances with different + * username in the User Credential node + * + * @throws Exception + */ + @Test + public void validateUniqueIdDifferentUserCredential() throws Exception { + PasspointConfiguration config1 = PasspointTestUtils.createConfig(); + Credential credential = createCredentialWithUserCredential("user", "passwd"); + config1.setCredential(credential); + + // Modify config2's username to a different value + PasspointConfiguration config2 = PasspointTestUtils.createConfig(); + credential = createCredentialWithUserCredential("user2", "passwd"); + config2.setCredential(credential); + + assertNotEquals(config1.getUniqueId(), config2.getUniqueId()); + } + + /** + * Verify that the unique identifier generated is different for two instances with different + * Cert Credential node + * + * @throws Exception + */ + @Test + public void validateUniqueIdDifferentCertCredential() throws Exception { + PasspointConfiguration config1 = PasspointTestUtils.createConfig(); + Credential credential = createCredentialWithCertificateCredential(true, true); + config1.setCredential(credential); + + // Modify config2's cert credential to a different set of values + PasspointConfiguration config2 = PasspointTestUtils.createConfig(); + credential = createCredentialWithCertificateCredential(false, false); + config2.setCredential(credential); + + assertNotEquals(config1.getUniqueId(), config2.getUniqueId()); + } + + /** + * Helper function for generating certificate credential for testing. + * + * @return {@link Credential} + */ + private static Credential createCredentialWithCertificateCredential(Boolean useCaCert0, + Boolean useCert0) + throws NoSuchAlgorithmException, CertificateEncodingException { + Credential.CertificateCredential certCred = new Credential.CertificateCredential(); + certCred.setCertType("x509v3"); + if (useCert0) { + certCred.setCertSha256Fingerprint( + MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded())); + } else { + certCred.setCertSha256Fingerprint(MessageDigest.getInstance("SHA-256") + .digest(FakeKeys.CLIENT_SUITE_B_RSA3072_CERT.getEncoded())); + } + return createCredential(null, certCred, null, new X509Certificate[] {FakeKeys.CLIENT_CERT}, + FakeKeys.RSA_KEY1, useCaCert0 ? FakeKeys.CA_CERT0 : FakeKeys.CA_CERT1); + } + + /** + * Helper function for generating user credential for testing. + * + * @return {@link Credential} + */ + private static Credential createCredentialWithUserCredential(String username, String password) { + Credential.UserCredential userCred = new Credential.UserCredential(); + userCred.setUsername(username); + userCred.setPassword(password); + userCred.setMachineManaged(true); + userCred.setAbleToShare(true); + userCred.setSoftTokenApp("TestApp"); + userCred.setEapType(EAPConstants.EAP_TTLS); + userCred.setNonEapInnerMethod("MS-CHAP"); + return createCredential(userCred, null, null, null, null, FakeKeys.CA_CERT0); + } + + /** + * Helper function for generating Credential for testing. + * + * @param userCred Instance of UserCredential + * @param certCred Instance of CertificateCredential + * @param simCred Instance of SimCredential + * @param clientCertificateChain Chain of client certificates + * @param clientPrivateKey Client private key + * @param caCerts CA certificates + * @return {@link Credential} + */ + private static Credential createCredential(Credential.UserCredential userCred, + Credential.CertificateCredential certCred, + Credential.SimCredential simCred, + X509Certificate[] clientCertificateChain, PrivateKey clientPrivateKey, + X509Certificate... caCerts) { + Credential cred = new Credential(); + cred.setCreationTimeInMillis(123455L); + cred.setExpirationTimeInMillis(2310093L); + cred.setRealm("realm"); + cred.setCheckAaaServerCertStatus(true); + cred.setUserCredential(userCred); + cred.setCertCredential(certCred); + cred.setSimCredential(simCred); + if (caCerts != null && caCerts.length == 1) { + cred.setCaCertificate(caCerts[0]); + } else { + cred.setCaCertificates(caCerts); + } + cred.setClientCertificateChain(clientCertificateChain); + cred.setClientPrivateKey(clientPrivateKey); + return cred; + } + + /** * Verify that the unique identifier API generates an exception if HomeSP is not initialized. * * @throws Exception diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java index 829d8f0a9a3a..a44df40a8e97 100644 --- a/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java +++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/CredentialTest.java @@ -593,10 +593,10 @@ public class CredentialTest { } /** - * Verify that unique identifiers are different for a credential with different values + * Verify that unique identifiers are different for a credential with different username */ @Test - public void testUniqueIdDifferentForUserCredentialsWithDifferentValues() throws Exception { + public void testUniqueIdDifferentForUserCredentialsWithDifferentUsername() throws Exception { Credential userCred1 = createCredentialWithUserCredential(); Credential userCred2 = createCredentialWithUserCredential(); userCred2.getUserCredential().setUsername("anotheruser"); @@ -605,7 +605,24 @@ public class CredentialTest { } /** - * Verify that unique identifiers are different for a credential with different values + * Verify that unique identifiers are different for a credential with different password and + * other values other than username + */ + @Test + public void testUniqueIdSameForUserCredentialsWithDifferentPassword() throws Exception { + Credential userCred1 = createCredentialWithUserCredential(); + Credential userCred2 = createCredentialWithUserCredential(); + userCred2.getUserCredential().setPassword("someotherpassword!"); + userCred2.getUserCredential().setMachineManaged(false); + userCred2.getUserCredential().setAbleToShare(false); + userCred2.getUserCredential().setSoftTokenApp("TestApp2"); + userCred2.getUserCredential().setNonEapInnerMethod("PAP"); + + assertEquals(userCred1.getUniqueId(), userCred2.getUniqueId()); + } + + /** + * Verify that unique identifiers are different for a cert credential with different values */ @Test public void testUniqueIdDifferentForCertCredentialsWithDifferentValues() throws Exception { |