Merge "[Bouncer] Add min margin bottom for window inset." into tm-dev
diff --git a/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java b/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java
index 53a3889..c572f82 100644
--- a/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java
+++ b/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java
@@ -32,8 +32,6 @@
import android.annotation.UserHandleAware;
import android.content.Context;
-import com.android.internal.util.FrameworkStatsLog;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Collections;
@@ -453,62 +451,6 @@
@Retention(RetentionPolicy.SOURCE)
public @interface ReasonCode {}
- private static final int EXEMPTION_REASON_SYSTEM_UID = FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__EXEMPTION_REASON__REASON_SYSTEM_UID;
- private static final int EXEMPTION_REASON_ALLOWLISTED_PACKAGE = FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__EXEMPTION_REASON__REASON_ALLOWLISTED_PACKAGE;
- private static final int EXEMPTION_REASON_COMPANION_DEVICE_MANAGER = FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__EXEMPTION_REASON__REASON_COMPANION_DEVICE_MANAGER;
- private static final int EXEMPTION_REASON_DEVICE_DEMO_MODE = FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__EXEMPTION_REASON__REASON_DEVICE_DEMO_MODE;
- private static final int EXEMPTION_REASON_DEVICE_OWNER = FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__EXEMPTION_REASON__REASON_DEVICE_OWNER;
- private static final int EXEMPTION_REASON_PROFILE_OWNER = FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__EXEMPTION_REASON__REASON_PROFILE_OWNER;
- private static final int EXEMPTION_REASON_PROC_STATE_PERSISTENT = FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__EXEMPTION_REASON__REASON_PROC_STATE_PERSISTENT;
- private static final int EXEMPTION_REASON_PROC_STATE_PERSISTENT_UI = FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__EXEMPTION_REASON__REASON_PROC_STATE_PERSISTENT_UI;
- private static final int EXEMPTION_REASON_OP_ACTIVATE_VPN = FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__EXEMPTION_REASON__REASON_OP_ACTIVATE_VPN;
- private static final int EXEMPTION_REASON_OP_ACTIVATE_PLATFORM_VPN = FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__EXEMPTION_REASON__REASON_OP_ACTIVATE_PLATFORM_VPN;
- private static final int EXEMPTION_REASON_SYSTEM_MODULE = FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__EXEMPTION_REASON__REASON_SYSTEM_MODULE;
- private static final int EXEMPTION_REASON_CARRIER_PRIVILEGED_APP = FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__EXEMPTION_REASON__REASON_CARRIER_PRIVILEGED_APP;
- private static final int EXEMPTION_REASON_SYSTEM_ALLOW_LISTED = FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__EXEMPTION_REASON__REASON_SYSTEM_ALLOW_LISTED;
- private static final int EXEMPTION_REASON_ROLE_DIALER = FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__EXEMPTION_REASON__REASON_ROLE_DIALER;
- private static final int EXEMPTION_REASON_ROLE_EMERGENCY = FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__EXEMPTION_REASON__REASON_ROLE_EMERGENCY;
- private static final int EXEMPTION_REASON_DENIED = FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__EXEMPTION_REASON__REASON_DENIED;
- /**
- * List of exemption reason codes used for statsd logging in AppBackgroundRestrictionsInfo atom.
- * @hide
- */
- @IntDef(prefix = { "EXEMPTION_REASON_" }, value = {
- EXEMPTION_REASON_SYSTEM_UID,
- EXEMPTION_REASON_ALLOWLISTED_PACKAGE,
- EXEMPTION_REASON_COMPANION_DEVICE_MANAGER,
- EXEMPTION_REASON_DEVICE_DEMO_MODE,
- EXEMPTION_REASON_DEVICE_OWNER,
- EXEMPTION_REASON_PROFILE_OWNER,
- EXEMPTION_REASON_PROC_STATE_PERSISTENT,
- EXEMPTION_REASON_PROC_STATE_PERSISTENT_UI,
- EXEMPTION_REASON_OP_ACTIVATE_VPN,
- EXEMPTION_REASON_OP_ACTIVATE_PLATFORM_VPN,
- EXEMPTION_REASON_SYSTEM_MODULE,
- EXEMPTION_REASON_CARRIER_PRIVILEGED_APP,
- EXEMPTION_REASON_SYSTEM_ALLOW_LISTED,
- EXEMPTION_REASON_ROLE_DIALER,
- EXEMPTION_REASON_ROLE_EMERGENCY,
- EXEMPTION_REASON_DENIED,
- })
- public @interface ExemptionReason {}
-
/**
* @hide
*/
@@ -679,40 +621,40 @@
* @hide
* @return the reason code mapped to statsd for the AppBackgroundRestrictionsInfo atom.
*/
- public static @ExemptionReason int getExemptionReasonForStatsd(@ReasonCode int reasonCode) {
+ public static int getExemptionReasonForStatsd(@ReasonCode int reasonCode) {
switch (reasonCode) {
case REASON_SYSTEM_UID:
- return EXEMPTION_REASON_SYSTEM_UID;
+ return AppBackgroundRestrictionsInfo.REASON_SYSTEM_UID;
case REASON_ALLOWLISTED_PACKAGE:
- return EXEMPTION_REASON_ALLOWLISTED_PACKAGE;
+ return AppBackgroundRestrictionsInfo.REASON_ALLOWLISTED_PACKAGE;
case REASON_COMPANION_DEVICE_MANAGER:
- return EXEMPTION_REASON_COMPANION_DEVICE_MANAGER;
+ return AppBackgroundRestrictionsInfo.REASON_COMPANION_DEVICE_MANAGER;
case REASON_DEVICE_DEMO_MODE:
- return EXEMPTION_REASON_DEVICE_DEMO_MODE;
+ return AppBackgroundRestrictionsInfo.REASON_DEVICE_DEMO_MODE;
case REASON_DEVICE_OWNER:
- return EXEMPTION_REASON_DEVICE_OWNER;
+ return AppBackgroundRestrictionsInfo.REASON_DEVICE_OWNER;
case REASON_PROFILE_OWNER:
- return EXEMPTION_REASON_PROFILE_OWNER;
+ return AppBackgroundRestrictionsInfo.REASON_PROFILE_OWNER;
case REASON_PROC_STATE_PERSISTENT:
- return EXEMPTION_REASON_PROC_STATE_PERSISTENT;
+ return AppBackgroundRestrictionsInfo.REASON_PROC_STATE_PERSISTENT;
case REASON_PROC_STATE_PERSISTENT_UI:
- return EXEMPTION_REASON_PROC_STATE_PERSISTENT_UI;
+ return AppBackgroundRestrictionsInfo.REASON_PROC_STATE_PERSISTENT_UI;
case REASON_OP_ACTIVATE_VPN:
- return EXEMPTION_REASON_OP_ACTIVATE_VPN;
+ return AppBackgroundRestrictionsInfo.REASON_OP_ACTIVATE_VPN;
case REASON_OP_ACTIVATE_PLATFORM_VPN:
- return EXEMPTION_REASON_OP_ACTIVATE_PLATFORM_VPN;
+ return AppBackgroundRestrictionsInfo.REASON_OP_ACTIVATE_PLATFORM_VPN;
case REASON_SYSTEM_MODULE:
- return EXEMPTION_REASON_SYSTEM_MODULE;
+ return AppBackgroundRestrictionsInfo.REASON_SYSTEM_MODULE;
case REASON_CARRIER_PRIVILEGED_APP:
- return EXEMPTION_REASON_CARRIER_PRIVILEGED_APP;
+ return AppBackgroundRestrictionsInfo.REASON_CARRIER_PRIVILEGED_APP;
case REASON_SYSTEM_ALLOW_LISTED:
- return EXEMPTION_REASON_SYSTEM_ALLOW_LISTED;
+ return AppBackgroundRestrictionsInfo.REASON_SYSTEM_ALLOW_LISTED;
case REASON_ROLE_DIALER:
- return EXEMPTION_REASON_ROLE_DIALER;
+ return AppBackgroundRestrictionsInfo.REASON_ROLE_DIALER;
case REASON_ROLE_EMERGENCY:
- return EXEMPTION_REASON_ROLE_EMERGENCY;
+ return AppBackgroundRestrictionsInfo.REASON_ROLE_EMERGENCY;
default:
- return EXEMPTION_REASON_DENIED;
+ return AppBackgroundRestrictionsInfo.REASON_DENIED;
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index 881453f..0e4887d 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -612,8 +612,7 @@
private static final boolean DEFAULT_KILL_ON_SCHEDULE_EXACT_ALARM_REVOKED = true;
- // TODO(b/226439802): Flip to true.
- private static final boolean DEFAULT_SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT = false;
+ private static final boolean DEFAULT_SCHEDULE_EXACT_ALARM_DENIED_BY_DEFAULT = true;
// Minimum futurity of a new alarm
public long MIN_FUTURITY = DEFAULT_MIN_FUTURITY;
diff --git a/core/java/android/accessibilityservice/InputMethod.java b/core/java/android/accessibilityservice/InputMethod.java
index a393604..79bac9b 100644
--- a/core/java/android/accessibilityservice/InputMethod.java
+++ b/core/java/android/accessibilityservice/InputMethod.java
@@ -62,7 +62,6 @@
private final AccessibilityService mService;
private InputBinding mInputBinding;
- private InputConnection mInputConnection;
private boolean mInputStarted;
private InputConnection mStartedInputConnection;
private EditorInfo mInputEditorInfo;
@@ -81,12 +80,8 @@
*/
@Nullable
public final AccessibilityInputConnection getCurrentInputConnection() {
- InputConnection ic = mStartedInputConnection;
- if (ic != null) {
- return new AccessibilityInputConnection(ic);
- }
- if (mInputConnection != null) {
- return new AccessibilityInputConnection(mInputConnection);
+ if (mStartedInputConnection != null) {
+ return new AccessibilityInputConnection(mStartedInputConnection);
}
return null;
}
@@ -136,10 +131,8 @@
* to perform whatever behavior you would like.
*/
public void onFinishInput() {
- InputConnection ic = mStartedInputConnection != null ? mStartedInputConnection
- : mInputConnection;
- if (ic != null) {
- ic.finishComposingText();
+ if (mStartedInputConnection != null) {
+ mStartedInputConnection.finishComposingText();
}
}
@@ -176,38 +169,38 @@
final void bindInput(@NonNull InputBinding binding) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AccessibilityService.bindInput");
mInputBinding = binding;
- mInputConnection = binding.getConnection();
- Log.v(LOG_TAG, "bindInput(): binding=" + binding
- + " ic=" + mInputConnection);
+ Log.v(LOG_TAG, "bindInput(): binding=" + binding);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
final void unbindInput() {
- Log.v(LOG_TAG, "unbindInput(): binding=" + mInputBinding
- + " ic=" + mInputConnection);
+ Log.v(LOG_TAG, "unbindInput(): binding=" + mInputBinding);
// Unbind input is per process per display.
mInputBinding = null;
- mInputConnection = null;
}
final void startInput(@Nullable InputConnection ic, @NonNull EditorInfo attribute) {
Log.v(LOG_TAG, "startInput(): editor=" + attribute);
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.startInput");
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AccessibilityService.startInput");
doStartInput(ic, attribute, false /* restarting */);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
final void restartInput(@Nullable InputConnection ic, @NonNull EditorInfo attribute) {
Log.v(LOG_TAG, "restartInput(): editor=" + attribute);
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.restartInput");
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AccessibilityService.restartInput");
doStartInput(ic, attribute, true /* restarting */);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
final void doStartInput(InputConnection ic, EditorInfo attribute, boolean restarting) {
- if (!restarting && mInputStarted) {
+ if ((ic == null || !restarting) && mInputStarted) {
doFinishInput();
+ if (ic == null) {
+ // Unlike InputMethodService, A11y IME should not observe fallback InputConnection.
+ return;
+ }
}
mInputStarted = true;
mStartedInputConnection = ic;
@@ -224,6 +217,7 @@
}
mInputStarted = false;
mStartedInputConnection = null;
+ mInputEditorInfo = null;
}
private InputMethodSession onCreateInputMethodSessionInterface() {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 852dd97..7d68eb9 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4114,8 +4114,8 @@
@NonNull SurfaceControl startingWindowLeash) {
final SplashScreenView.Builder builder = new SplashScreenView.Builder(r.activity);
final SplashScreenView view = builder.createFromParcel(parcelable).build();
+ view.attachHostWindow(r.window);
decorView.addView(view);
- view.attachHostActivityAndSetSystemUIColors(r.activity, r.window);
view.requestLayout();
view.getViewTreeObserver().addOnDrawListener(new ViewTreeObserver.OnDrawListener() {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index bfb1168..56d655c 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2813,8 +2813,8 @@
}
if (extras != null) {
- visitIconUri(visitor, extras.getParcelable(EXTRA_LARGE_ICON_BIG));
- visitIconUri(visitor, extras.getParcelable(EXTRA_PICTURE_ICON));
+ visitIconUri(visitor, extras.getParcelable(EXTRA_LARGE_ICON_BIG, Icon.class));
+ visitIconUri(visitor, extras.getParcelable(EXTRA_PICTURE_ICON, Icon.class));
// NOTE: The documentation of EXTRA_AUDIO_CONTENTS_URI explicitly says that it is a
// String representation of a Uri, but the previous implementation (and unit test) of
@@ -2838,7 +2838,7 @@
}
}
- final Person person = extras.getParcelable(EXTRA_MESSAGING_PERSON);
+ final Person person = extras.getParcelable(EXTRA_MESSAGING_PERSON, Person.class);
if (person != null) {
visitor.accept(person.getIconUri());
}
@@ -6473,7 +6473,7 @@
public static Notification.Builder recoverBuilder(Context context, Notification n) {
// Re-create notification context so we can access app resources.
ApplicationInfo applicationInfo = n.extras.getParcelable(
- EXTRA_BUILDER_APPLICATION_INFO);
+ EXTRA_BUILDER_APPLICATION_INFO, ApplicationInfo.class);
Context builderContext;
if (applicationInfo != null) {
try {
@@ -6925,9 +6925,8 @@
boolean isMediaStyle = (MediaStyle.class.equals(style)
|| DecoratedMediaCustomViewStyle.class.equals(style));
- boolean hasMediaSession = (extras.getParcelable(Notification.EXTRA_MEDIA_SESSION) != null
- && extras.getParcelable(Notification.EXTRA_MEDIA_SESSION)
- instanceof MediaSession.Token);
+ boolean hasMediaSession = extras.getParcelable(Notification.EXTRA_MEDIA_SESSION,
+ MediaSession.Token.class) != null;
return isMediaStyle && hasMediaSession;
}
@@ -7522,7 +7521,7 @@
if (extras.containsKey(EXTRA_LARGE_ICON_BIG)) {
mBigLargeIconSet = true;
- mBigLargeIcon = extras.getParcelable(EXTRA_LARGE_ICON_BIG);
+ mBigLargeIcon = extras.getParcelable(EXTRA_LARGE_ICON_BIG, Icon.class);
}
if (extras.containsKey(EXTRA_PICTURE_CONTENT_DESCRIPTION)) {
@@ -7542,11 +7541,11 @@
// When this style adds a picture, we only add one of the keys. If both were added,
// it would most likely be a legacy app trying to override the picture in some way.
// Because of that case it's better to give precedence to the legacy field.
- Bitmap bitmapPicture = extras.getParcelable(EXTRA_PICTURE);
+ Bitmap bitmapPicture = extras.getParcelable(EXTRA_PICTURE, Bitmap.class);
if (bitmapPicture != null) {
return Icon.createWithBitmap(bitmapPicture);
} else {
- return extras.getParcelable(EXTRA_PICTURE_ICON);
+ return extras.getParcelable(EXTRA_PICTURE_ICON, Icon.class);
}
}
@@ -8165,7 +8164,7 @@
protected void restoreFromExtras(Bundle extras) {
super.restoreFromExtras(extras);
- mUser = extras.getParcelable(EXTRA_MESSAGING_PERSON);
+ mUser = extras.getParcelable(EXTRA_MESSAGING_PERSON, Person.class);
if (mUser == null) {
CharSequence displayName = extras.getCharSequence(EXTRA_SELF_DISPLAY_NAME);
mUser = new Person.Builder().setName(displayName).build();
@@ -8177,7 +8176,7 @@
mHistoricMessages = Message.getMessagesFromBundleArray(histMessages);
mIsGroupConversation = extras.getBoolean(EXTRA_IS_GROUP_CONVERSATION);
mUnreadMessageCount = extras.getInt(EXTRA_CONVERSATION_UNREAD_MESSAGE_COUNT);
- mShortcutIcon = extras.getParcelable(EXTRA_CONVERSATION_ICON);
+ mShortcutIcon = extras.getParcelable(EXTRA_CONVERSATION_ICON, Icon.class);
}
/**
@@ -8731,7 +8730,7 @@
return null;
} else {
- Person senderPerson = bundle.getParcelable(KEY_SENDER_PERSON);
+ Person senderPerson = bundle.getParcelable(KEY_SENDER_PERSON, Person.class);
if (senderPerson == null) {
// Legacy apps that use compat don't actually provide the sender objects
// We need to fix the compat version to provide people / use
@@ -8748,7 +8747,7 @@
if (bundle.containsKey(KEY_DATA_MIME_TYPE) &&
bundle.containsKey(KEY_DATA_URI)) {
message.setData(bundle.getString(KEY_DATA_MIME_TYPE),
- (Uri) bundle.getParcelable(KEY_DATA_URI));
+ bundle.getParcelable(KEY_DATA_URI, Uri.class));
}
if (bundle.containsKey(KEY_EXTRAS_BUNDLE)) {
message.getExtras().putAll(bundle.getBundle(KEY_EXTRAS_BUNDLE));
@@ -9154,7 +9153,7 @@
super.restoreFromExtras(extras);
if (extras.containsKey(EXTRA_MEDIA_SESSION)) {
- mToken = extras.getParcelable(EXTRA_MEDIA_SESSION);
+ mToken = extras.getParcelable(EXTRA_MEDIA_SESSION, MediaSession.Token.class);
}
if (extras.containsKey(EXTRA_COMPACT_ACTIONS)) {
mActionsToShowInCompact = extras.getIntArray(EXTRA_COMPACT_ACTIONS);
@@ -9166,7 +9165,8 @@
mDeviceIcon = extras.getInt(EXTRA_MEDIA_REMOTE_ICON);
}
if (extras.containsKey(EXTRA_MEDIA_REMOTE_INTENT)) {
- mDeviceIntent = extras.getParcelable(EXTRA_MEDIA_REMOTE_INTENT);
+ mDeviceIntent = extras.getParcelable(
+ EXTRA_MEDIA_REMOTE_INTENT, PendingIntent.class);
}
}
@@ -9758,12 +9758,12 @@
super.restoreFromExtras(extras);
mCallType = extras.getInt(EXTRA_CALL_TYPE);
mIsVideo = extras.getBoolean(EXTRA_CALL_IS_VIDEO);
- mPerson = extras.getParcelable(EXTRA_CALL_PERSON);
+ mPerson = extras.getParcelable(EXTRA_CALL_PERSON, Person.class);
mVerificationIcon = extras.getParcelable(EXTRA_VERIFICATION_ICON);
mVerificationText = extras.getCharSequence(EXTRA_VERIFICATION_TEXT);
- mAnswerIntent = extras.getParcelable(EXTRA_ANSWER_INTENT);
- mDeclineIntent = extras.getParcelable(EXTRA_DECLINE_INTENT);
- mHangUpIntent = extras.getParcelable(EXTRA_HANG_UP_INTENT);
+ mAnswerIntent = extras.getParcelable(EXTRA_ANSWER_INTENT, PendingIntent.class);
+ mDeclineIntent = extras.getParcelable(EXTRA_DECLINE_INTENT, PendingIntent.class);
+ mHangUpIntent = extras.getParcelable(EXTRA_HANG_UP_INTENT, PendingIntent.class);
mAnswerButtonColor = extras.containsKey(EXTRA_ANSWER_COLOR)
? extras.getInt(EXTRA_ANSWER_COLOR) : null;
mDeclineButtonColor = extras.containsKey(EXTRA_DECLINE_COLOR)
@@ -10824,9 +10824,9 @@
// Keys within EXTRA_WEARABLE_EXTENSIONS for wearable options.
private static final String KEY_ACTIONS = "actions";
private static final String KEY_FLAGS = "flags";
- private static final String KEY_DISPLAY_INTENT = "displayIntent";
+ static final String KEY_DISPLAY_INTENT = "displayIntent";
private static final String KEY_PAGES = "pages";
- private static final String KEY_BACKGROUND = "background";
+ static final String KEY_BACKGROUND = "background";
private static final String KEY_CONTENT_ICON = "contentIcon";
private static final String KEY_CONTENT_ICON_GRAVITY = "contentIconGravity";
private static final String KEY_CONTENT_ACTION_INDEX = "contentActionIndex";
@@ -10883,7 +10883,8 @@
}
mFlags = wearableBundle.getInt(KEY_FLAGS, DEFAULT_FLAGS);
- mDisplayIntent = wearableBundle.getParcelable(KEY_DISPLAY_INTENT);
+ mDisplayIntent = wearableBundle.getParcelable(
+ KEY_DISPLAY_INTENT, PendingIntent.class);
Notification[] pages = getParcelableArrayFromBundle(
wearableBundle, KEY_PAGES, Notification.class);
@@ -10891,7 +10892,7 @@
Collections.addAll(mPages, pages);
}
- mBackground = wearableBundle.getParcelable(KEY_BACKGROUND);
+ mBackground = wearableBundle.getParcelable(KEY_BACKGROUND, Bitmap.class);
mContentIcon = wearableBundle.getInt(KEY_CONTENT_ICON);
mContentIconGravity = wearableBundle.getInt(KEY_CONTENT_ICON_GRAVITY,
DEFAULT_CONTENT_ICON_GRAVITY);
@@ -11604,7 +11605,7 @@
Bundle carBundle = notif.extras == null ?
null : notif.extras.getBundle(EXTRA_CAR_EXTENDER);
if (carBundle != null) {
- mLargeIcon = carBundle.getParcelable(EXTRA_LARGE_ICON);
+ mLargeIcon = carBundle.getParcelable(EXTRA_LARGE_ICON, Bitmap.class);
mColor = carBundle.getInt(EXTRA_COLOR, Notification.COLOR_DEFAULT);
Bundle b = carBundle.getBundle(EXTRA_CONVERSATION);
@@ -11710,9 +11711,9 @@
private static final String KEY_AUTHOR = "author";
private static final String KEY_TEXT = "text";
private static final String KEY_MESSAGES = "messages";
- private static final String KEY_REMOTE_INPUT = "remote_input";
- private static final String KEY_ON_REPLY = "on_reply";
- private static final String KEY_ON_READ = "on_read";
+ static final String KEY_REMOTE_INPUT = "remote_input";
+ static final String KEY_ON_REPLY = "on_reply";
+ static final String KEY_ON_READ = "on_read";
private static final String KEY_PARTICIPANTS = "participants";
private static final String KEY_TIMESTAMP = "timestamp";
@@ -11837,10 +11838,10 @@
}
}
- PendingIntent onRead = b.getParcelable(KEY_ON_READ);
- PendingIntent onReply = b.getParcelable(KEY_ON_REPLY);
+ PendingIntent onRead = b.getParcelable(KEY_ON_READ, PendingIntent.class);
+ PendingIntent onReply = b.getParcelable(KEY_ON_REPLY, PendingIntent.class);
- RemoteInput remoteInput = b.getParcelable(KEY_REMOTE_INPUT);
+ RemoteInput remoteInput = b.getParcelable(KEY_REMOTE_INPUT, RemoteInput.class);
String[] participants = b.getStringArray(KEY_PARTICIPANTS);
if (participants == null || participants.length != 1) {
@@ -11982,8 +11983,8 @@
private static final String EXTRA_TV_EXTENDER = "android.tv.EXTENSIONS";
private static final String EXTRA_FLAGS = "flags";
- private static final String EXTRA_CONTENT_INTENT = "content_intent";
- private static final String EXTRA_DELETE_INTENT = "delete_intent";
+ static final String EXTRA_CONTENT_INTENT = "content_intent";
+ static final String EXTRA_DELETE_INTENT = "delete_intent";
private static final String EXTRA_CHANNEL_ID = "channel_id";
private static final String EXTRA_SUPPRESS_SHOW_OVER_APPS = "suppressShowOverApps";
@@ -12015,8 +12016,8 @@
mFlags = bundle.getInt(EXTRA_FLAGS);
mChannelId = bundle.getString(EXTRA_CHANNEL_ID);
mSuppressShowOverApps = bundle.getBoolean(EXTRA_SUPPRESS_SHOW_OVER_APPS);
- mContentIntent = bundle.getParcelable(EXTRA_CONTENT_INTENT);
- mDeleteIntent = bundle.getParcelable(EXTRA_DELETE_INTENT);
+ mContentIntent = bundle.getParcelable(EXTRA_CONTENT_INTENT, PendingIntent.class);
+ mDeleteIntent = bundle.getParcelable(EXTRA_DELETE_INTENT, PendingIntent.class);
}
}
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 0a18588..e022ca3 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -67,7 +67,6 @@
import android.os.RemoteException;
import android.os.StrictMode;
import android.os.SystemProperties;
-import android.service.wallpaper.WallpaperService;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -559,23 +558,26 @@
}
mCachedWallpaper = null;
mCachedWallpaperUserId = 0;
- try {
- mCachedWallpaper = getCurrentWallpaperLocked(
- context, userId, hardware, cmProxy);
- mCachedWallpaperUserId = userId;
- } catch (OutOfMemoryError e) {
- Log.w(TAG, "Out of memory loading the current wallpaper: " + e);
- } catch (SecurityException e) {
- if (context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.O_MR1) {
- Log.w(TAG, "No permission to access wallpaper, suppressing"
- + " exception to avoid crashing legacy app.");
- } else {
- // Post-O apps really most sincerely need the permission.
- throw e;
+ }
+ try {
+ Bitmap currentWallpaper = getCurrentWallpaperLocked(
+ context, userId, hardware, cmProxy);
+ if (currentWallpaper != null) {
+ synchronized (this) {
+ mCachedWallpaper = currentWallpaper;
+ mCachedWallpaperUserId = userId;
+ return mCachedWallpaper;
}
}
- if (mCachedWallpaper != null) {
- return mCachedWallpaper;
+ } catch (OutOfMemoryError e) {
+ Log.w(TAG, "Out of memory loading the current wallpaper: " + e);
+ } catch (SecurityException e) {
+ if (context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.O_MR1) {
+ Log.w(TAG, "No permission to access wallpaper, suppressing"
+ + " exception to avoid crashing legacy app.");
+ } else {
+ // Post-O apps really most sincerely need the permission.
+ throw e;
}
}
if (returnDefault) {
@@ -2472,7 +2474,7 @@
*
* @param colors Wallpaper color info, {@code null} when not available.
* @param which A combination of {@link #FLAG_LOCK} and {@link #FLAG_SYSTEM}
- * @see WallpaperService.Engine#onComputeColors()
+ * @see android.service.wallpaper.WallpaperService.Engine#onComputeColors()
*/
void onColorsChanged(@Nullable WallpaperColors colors, int which);
@@ -2484,7 +2486,7 @@
* @param colors Wallpaper color info, {@code null} when not available.
* @param which A combination of {@link #FLAG_LOCK} and {@link #FLAG_SYSTEM}
* @param userId Owner of the wallpaper
- * @see WallpaperService.Engine#onComputeColors()
+ * @see android.service.wallpaper.WallpaperService.Engine#onComputeColors()
* @hide
*/
default void onColorsChanged(@Nullable WallpaperColors colors, int which, int userId) {
diff --git a/core/java/android/hardware/fingerprint/FingerprintStateListener.java b/core/java/android/hardware/biometrics/BiometricStateListener.java
similarity index 79%
rename from core/java/android/hardware/fingerprint/FingerprintStateListener.java
rename to core/java/android/hardware/biometrics/BiometricStateListener.java
index 551f512..2ac0c1e 100644
--- a/core/java/android/hardware/fingerprint/FingerprintStateListener.java
+++ b/core/java/android/hardware/biometrics/BiometricStateListener.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.hardware.fingerprint;
+package android.hardware.biometrics;
import android.annotation.IntDef;
@@ -22,10 +22,10 @@
import java.lang.annotation.RetentionPolicy;
/**
- * Interface for handling state changes in fingerprint-related events.
+ * Interface for handling state changes in biometric sensors.
* @hide
*/
-public abstract class FingerprintStateListener extends IFingerprintStateListener.Stub {
+public abstract class BiometricStateListener extends IBiometricStateListener.Stub {
// Operation has not started yet.
public static final int STATE_IDLE = 0;
@@ -43,16 +43,19 @@
@IntDef({STATE_IDLE, STATE_ENROLLING, STATE_KEYGUARD_AUTH, STATE_BP_AUTH, STATE_AUTH_OTHER})
@Retention(RetentionPolicy.SOURCE)
- public @interface State {}
+ public @interface State {
+ }
/**
* Defines behavior in response to state update
- * @param newState new state of fingerprint sensor
+ * @param newState new state of the biometric sensor
*/
- public void onStateChanged(@FingerprintStateListener.State int newState) {}
+ public void onStateChanged(@BiometricStateListener.State int newState) {
+ }
/**
* Invoked when enrollment state changes for the specified user
*/
- public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) {}
+ public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) {
+ }
}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintStateListener.aidl b/core/java/android/hardware/biometrics/IBiometricStateListener.aidl
similarity index 69%
rename from core/java/android/hardware/fingerprint/IFingerprintStateListener.aidl
rename to core/java/android/hardware/biometrics/IBiometricStateListener.aidl
index 1aa6fa1..5bdced0 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintStateListener.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricStateListener.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2022 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,16 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.hardware.fingerprint;
-
-import android.hardware.fingerprint.Fingerprint;
+package android.hardware.biometrics;
/**
- * Communication channel for FingerprintManager to register the FingerprintStateListener
- * in FingerprintService.
+ * Communication channel between <Biometric>Manager and <Biometric>Service for passing the
+ * listener.
* @hide
*/
-oneway interface IFingerprintStateListener {
+oneway interface IBiometricStateListener {
void onStateChanged(int newState);
void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments);
}
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 60c4b52..28f1f02 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -45,6 +45,7 @@
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricFingerprintConstants;
import android.hardware.biometrics.BiometricPrompt;
+import android.hardware.biometrics.BiometricStateListener;
import android.hardware.biometrics.BiometricTestSession;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.biometrics.SensorProperties;
@@ -918,13 +919,13 @@
/**
- * Forwards FingerprintStateListener to FingerprintService
- * @param listener new FingerprintStateListener being added
+ * Forwards BiometricStateListener to FingerprintService
+ * @param listener new BiometricStateListener being added
* @hide
*/
- public void registerFingerprintStateListener(@NonNull FingerprintStateListener listener) {
+ public void registerBiometricStateListener(@NonNull BiometricStateListener listener) {
try {
- mService.registerFingerprintStateListener(listener);
+ mService.registerBiometricStateListener(listener);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index d60bb6e..0b63446 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -17,13 +17,13 @@
import android.hardware.biometrics.IBiometricSensorReceiver;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
+import android.hardware.biometrics.IBiometricStateListener;
import android.hardware.biometrics.IInvalidationCallback;
import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.ITestSessionCallback;
import android.hardware.fingerprint.IFingerprintClientActiveCallback;
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
-import android.hardware.fingerprint.IFingerprintStateListener;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.hardware.fingerprint.ISidefpsController;
import android.hardware.fingerprint.Fingerprint;
@@ -169,6 +169,6 @@
// Sets the controller for managing the SideFPS overlay.
void setSidefpsController(in ISidefpsController controller);
- // Registers FingerprintStateListener in list stored by FingerprintService.
- void registerFingerprintStateListener(IFingerprintStateListener listener);
+ // Registers BiometricStateListener.
+ void registerBiometricStateListener(IBiometricStateListener listener);
}
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index 390c3b9..f1b110a 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -172,11 +172,11 @@
*
* <p>An app that has carrier privileges for any of the subscriptions in the given group may
* clear a VCN configuration. This API is ONLY permitted for callers running as the primary
- * user. Any active VCN will be torn down.
+ * user. Any active VCN associated with this configuration will be torn down.
*
* @param subscriptionGroup the subscription group that the configuration should be applied to
- * @throws SecurityException if the caller does not have carrier privileges, or is not running
- * as the primary user
+ * @throws SecurityException if the caller does not have carrier privileges, is not the owner of
+ * the associated configuration, or is not running as the primary user
* @throws IOException if the configuration failed to be cleared from disk. This may occur due
* to temporary disk errors, or more permanent conditions such as a full disk.
*/
@@ -196,8 +196,13 @@
/**
* Retrieves the list of Subscription Groups for which a VCN Configuration has been set.
*
- * <p>The returned list will include only subscription groups for which the carrier app is
- * privileged, and which have an associated {@link VcnConfig}.
+ * <p>The returned list will include only subscription groups for which an associated {@link
+ * VcnConfig} exists, and the app is either:
+ *
+ * <ul>
+ * <li>Carrier privileged for that subscription group, or
+ * <li>Is the provisioning package of the config
+ * </ul>
*
* @throws SecurityException if the caller is not running as the primary user
*/
diff --git a/core/java/android/service/dreams/DreamActivity.java b/core/java/android/service/dreams/DreamActivity.java
index 96bbf8e..cf4e6a6 100644
--- a/core/java/android/service/dreams/DreamActivity.java
+++ b/core/java/android/service/dreams/DreamActivity.java
@@ -19,6 +19,7 @@
import android.annotation.Nullable;
import android.app.Activity;
import android.os.Bundle;
+import android.text.TextUtils;
import com.android.internal.R;
@@ -44,6 +45,7 @@
*/
public class DreamActivity extends Activity {
static final String EXTRA_CALLBACK = "binder";
+ static final String EXTRA_DREAM_TITLE = "title";
public DreamActivity() {}
@@ -51,6 +53,11 @@
public void onCreate(@Nullable Bundle bundle) {
super.onCreate(bundle);
+ final String title = getIntent().getStringExtra(EXTRA_DREAM_TITLE);
+ if (!TextUtils.isEmpty(title)) {
+ setTitle(title);
+ }
+
DreamService.DreamServiceWrapper callback =
(DreamService.DreamServiceWrapper) getIntent().getIBinderExtra(EXTRA_CALLBACK);
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index d4f8a3b..95eae6c 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -1280,6 +1280,9 @@
i.setPackage(getApplicationContext().getPackageName());
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.putExtra(DreamActivity.EXTRA_CALLBACK, mDreamServiceWrapper);
+ final ServiceInfo serviceInfo = fetchServiceInfo(this,
+ new ComponentName(this, getClass()));
+ i.putExtra(DreamActivity.EXTRA_DREAM_TITLE, fetchDreamLabel(this, serviceInfo));
try {
if (!ActivityTaskManager.getService().startDreamActivity(i)) {
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 5131e4e..425dbb9 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -1685,13 +1685,12 @@
void updatePage(EngineWindowPage currentPage, int pageIndx, int numPages,
float xOffsetStep) {
- // to save creating a runnable, check twice
- long current = System.currentTimeMillis();
+ // in case the clock is zero, we start with negative time
+ long current = SystemClock.elapsedRealtime() - DEFAULT_UPDATE_SCREENSHOT_DURATION;
long lapsed = current - currentPage.getLastUpdateTime();
// Always update the page when the last update time is <= 0
// This is important especially when the device first boots
- if (lapsed < DEFAULT_UPDATE_SCREENSHOT_DURATION
- && currentPage.getLastUpdateTime() > 0) {
+ if (lapsed < DEFAULT_UPDATE_SCREENSHOT_DURATION) {
return;
}
Surface surface = mSurfaceHolder.getSurface();
diff --git a/core/java/android/transparency/OWNERS b/core/java/android/transparency/OWNERS
index 75bf84c..ed0e5e5 100644
--- a/core/java/android/transparency/OWNERS
+++ b/core/java/android/transparency/OWNERS
@@ -1,4 +1,5 @@
-# Bug component: 36824
+# Bug component: 1164579
billylau@google.com
-vishwath@google.com
mpgroover@google.com
+vishwath@google.com
+wenhaowang@google.com
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 6be6f9d..96b1abb 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -1274,6 +1274,7 @@
private class SurfaceViewPositionUpdateListener implements RenderNode.PositionUpdateListener {
private final int mRtSurfaceWidth;
private final int mRtSurfaceHeight;
+ private boolean mRtFirst = true;
private final SurfaceControl.Transaction mPositionChangedTransaction =
new SurfaceControl.Transaction();
@@ -1284,14 +1285,15 @@
@Override
public void positionChanged(long frameNumber, int left, int top, int right, int bottom) {
- if (mRTLastReportedPosition.left == left
+ if (!mRtFirst && (mRTLastReportedPosition.left == left
&& mRTLastReportedPosition.top == top
&& mRTLastReportedPosition.right == right
&& mRTLastReportedPosition.bottom == bottom
&& mRTLastReportedSurfaceSize.x == mRtSurfaceWidth
- && mRTLastReportedSurfaceSize.y == mRtSurfaceHeight) {
+ && mRTLastReportedSurfaceSize.y == mRtSurfaceHeight)) {
return;
}
+ mRtFirst = false;
try {
if (DEBUG_POSITION) {
Log.d(TAG, String.format(
diff --git a/core/java/android/window/BackEvent.java b/core/java/android/window/BackEvent.java
index 14985c9..1024e2e 100644
--- a/core/java/android/window/BackEvent.java
+++ b/core/java/android/window/BackEvent.java
@@ -46,8 +46,8 @@
@Retention(RetentionPolicy.SOURCE)
public @interface SwipeEdge{}
- private final int mTouchX;
- private final int mTouchY;
+ private final float mTouchX;
+ private final float mTouchY;
private final float mProgress;
@SwipeEdge
@@ -58,14 +58,14 @@
/**
* Creates a new {@link BackEvent} instance.
*
- * @param touchX Absolute X location of the touch point.
- * @param touchY Absolute Y location of the touch point.
+ * @param touchX Absolute X location of the touch point of this event.
+ * @param touchY Absolute Y location of the touch point of this event.
* @param progress Value between 0 and 1 on how far along the back gesture is.
* @param swipeEdge Indicates which edge the swipe starts from.
* @param departingAnimationTarget The remote animation target of the departing application
* window.
*/
- public BackEvent(int touchX, int touchY, float progress, @SwipeEdge int swipeEdge,
+ public BackEvent(float touchX, float touchY, float progress, @SwipeEdge int swipeEdge,
@Nullable RemoteAnimationTarget departingAnimationTarget) {
mTouchX = touchX;
mTouchY = touchY;
@@ -75,8 +75,8 @@
}
private BackEvent(@NonNull Parcel in) {
- mTouchX = in.readInt();
- mTouchY = in.readInt();
+ mTouchX = in.readFloat();
+ mTouchY = in.readFloat();
mProgress = in.readFloat();
mSwipeEdge = in.readInt();
mDepartingAnimationTarget = in.readTypedObject(RemoteAnimationTarget.CREATOR);
@@ -101,8 +101,8 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeInt(mTouchX);
- dest.writeInt(mTouchY);
+ dest.writeFloat(mTouchX);
+ dest.writeFloat(mTouchY);
dest.writeFloat(mProgress);
dest.writeInt(mSwipeEdge);
dest.writeTypedObject(mDepartingAnimationTarget, flags);
@@ -118,14 +118,14 @@
/**
* Returns the absolute X location of the touch point.
*/
- public int getTouchX() {
+ public float getTouchX() {
return mTouchX;
}
/**
* Returns the absolute Y location of the touch point.
*/
- public int getTouchY() {
+ public float getTouchY() {
return mTouchY;
}
diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java
index 2d1deb2..bc9f74e 100644
--- a/core/java/android/window/SplashScreenView.java
+++ b/core/java/android/window/SplashScreenView.java
@@ -16,9 +16,6 @@
package android.window;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
-import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
-import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_SPLASHSCREEN_AVD;
@@ -29,11 +26,9 @@
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.annotation.UiThread;
-import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
@@ -52,15 +47,12 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
-import android.view.WindowInsetsController;
-import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
import com.android.internal.R;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.policy.DecorView;
-import com.android.internal.util.ContrastColorUtil;
import java.time.Duration;
import java.time.Instant;
@@ -87,12 +79,6 @@
private static final String TAG = SplashScreenView.class.getSimpleName();
private static final boolean DEBUG = Build.IS_DEBUGGABLE;
- private static final int LIGHT_BARS_MASK =
- WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS
- | WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
- private static final int WINDOW_FLAG_MASK = FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
- | FLAG_TRANSLUCENT_NAVIGATION | FLAG_TRANSLUCENT_STATUS;
-
private boolean mNotCopyable;
private boolean mIsCopied;
private int mInitBackgroundColor;
@@ -107,9 +93,6 @@
private final Rect mTmpRect = new Rect();
private final int[] mTmpPos = new int[2];
- // The host activity when transfer view to it.
- private Activity mHostActivity;
-
@Nullable
private SurfaceControlViewHost.SurfacePackage mSurfacePackageCopy;
@Nullable
@@ -123,14 +106,7 @@
// cache original window and status
private Window mWindow;
- private int mAppWindowFlags;
- private int mStatusBarColor;
- private int mNavigationBarColor;
- private int mSystemBarsAppearance;
private boolean mHasRemoved;
- private boolean mNavigationContrastEnforced;
- private boolean mStatusContrastEnforced;
- private boolean mDecorFitsSystemWindows;
/**
* Internal builder to create a SplashScreenView object.
@@ -570,7 +546,6 @@
if (decorView != null) {
decorView.removeView(this);
}
- restoreSystemUIColors();
mWindow = null;
}
mHasRemoved = true;
@@ -651,56 +626,12 @@
}
/**
- * Called when this view is attached to an activity. This also makes SystemUI colors
- * transparent so the content of splash screen view can draw fully.
+ * Called when this view is attached to a window of an activity.
*
* @hide
*/
- public void attachHostActivityAndSetSystemUIColors(Activity activity, Window window) {
- mHostActivity = activity;
+ public void attachHostWindow(Window window) {
mWindow = window;
- final WindowManager.LayoutParams attr = window.getAttributes();
- mAppWindowFlags = attr.flags;
- mStatusBarColor = window.getStatusBarColor();
- mNavigationBarColor = window.getNavigationBarColor();
- mSystemBarsAppearance = window.getInsetsController().getSystemBarsAppearance();
- mNavigationContrastEnforced = window.isNavigationBarContrastEnforced();
- mStatusContrastEnforced = window.isStatusBarContrastEnforced();
- mDecorFitsSystemWindows = window.decorFitsSystemWindows();
-
- applySystemBarsContrastColor(window.getInsetsController(), mInitBackgroundColor);
- // Let app draw the background of bars.
- window.addFlags(FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
- // Use specified bar colors instead of window background.
- window.clearFlags(FLAG_TRANSLUCENT_STATUS | FLAG_TRANSLUCENT_NAVIGATION);
- window.setStatusBarColor(Color.TRANSPARENT);
- window.setNavigationBarColor(Color.TRANSPARENT);
- window.setDecorFitsSystemWindows(false);
- window.setStatusBarContrastEnforced(false);
- window.setNavigationBarContrastEnforced(false);
- }
-
- /** Called when this view is removed from the host activity. */
- private void restoreSystemUIColors() {
- mWindow.setFlags(mAppWindowFlags, WINDOW_FLAG_MASK);
- mWindow.setStatusBarColor(mStatusBarColor);
- mWindow.setNavigationBarColor(mNavigationBarColor);
- mWindow.getInsetsController().setSystemBarsAppearance(mSystemBarsAppearance,
- LIGHT_BARS_MASK);
- mWindow.setDecorFitsSystemWindows(mDecorFitsSystemWindows);
- mWindow.setStatusBarContrastEnforced(mStatusContrastEnforced);
- mWindow.setNavigationBarContrastEnforced(mNavigationContrastEnforced);
- }
-
- /**
- * Makes the icon color of system bars contrast.
- * @hide
- */
- public static void applySystemBarsContrastColor(WindowInsetsController windowInsetsController,
- int backgroundColor) {
- final int lightBarAppearance = ContrastColorUtil.isColorLight(backgroundColor)
- ? LIGHT_BARS_MASK : 0;
- windowInsetsController.setSystemBarsAppearance(lightBarAppearance, LIGHT_BARS_MASK);
}
/**
diff --git a/core/java/com/android/internal/policy/ForceShowNavigationBarSettingsObserver.java b/core/java/com/android/internal/policy/KidsModeSettingsObserver.java
similarity index 85%
rename from core/java/com/android/internal/policy/ForceShowNavigationBarSettingsObserver.java
rename to core/java/com/android/internal/policy/KidsModeSettingsObserver.java
index 75dce5a..8a1d407 100644
--- a/core/java/com/android/internal/policy/ForceShowNavigationBarSettingsObserver.java
+++ b/core/java/com/android/internal/policy/KidsModeSettingsObserver.java
@@ -24,17 +24,17 @@
import android.provider.Settings;
/**
- * A ContentObserver for listening force show navigation bar relative setting keys:
+ * A ContentObserver for listening kids mode relative setting keys:
* - {@link Settings.Secure#NAVIGATION_MODE}
- * - {@link Settings.Secure#NAV_BAR_FORCE_VISIBLE}
+ * - {@link Settings.Secure#NAV_BAR_KIDS_MODE}
*
* @hide
*/
-public class ForceShowNavigationBarSettingsObserver extends ContentObserver {
+public class KidsModeSettingsObserver extends ContentObserver {
private Context mContext;
private Runnable mOnChangeRunnable;
- public ForceShowNavigationBarSettingsObserver(Handler handler, Context context) {
+ public KidsModeSettingsObserver(Handler handler, Context context) {
super(handler);
mContext = context;
}
@@ -52,7 +52,7 @@
Settings.Secure.getUriFor(Settings.Secure.NAVIGATION_MODE),
false, this, UserHandle.USER_ALL);
r.registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.NAV_BAR_FORCE_VISIBLE),
+ Settings.Secure.getUriFor(Settings.Secure.NAV_BAR_KIDS_MODE),
false, this, UserHandle.USER_ALL);
}
@@ -78,6 +78,6 @@
return Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.NAVIGATION_MODE, 0, UserHandle.USER_CURRENT) == 0
&& Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.NAV_BAR_FORCE_VISIBLE, 0, UserHandle.USER_CURRENT) == 1;
+ Settings.Secure.NAV_BAR_KIDS_MODE, 0, UserHandle.USER_CURRENT) == 1;
}
}
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index 3f7c4d5..2f707a7 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -48,7 +48,7 @@
*/
public class LatencyTracker {
private static final String TAG = "LatencyTracker";
- private static final String SETTINGS_ENABLED_KEY = "enabled";
+ public static final String SETTINGS_ENABLED_KEY = "enabled";
private static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval";
private static final boolean DEBUG = false;
/** Default to being enabled on debug builds. */
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 0e3840a..757f409 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -674,6 +674,10 @@
<!-- Indicates whether to enable hinge angle sensor when using unfold animation -->
<bool name="config_unfoldTransitionHingeAngle">false</bool>
+ <!-- Indicates the time needed to time out the fold animation if the device stops in half folded
+ mode. -->
+ <integer name="config_unfoldTransitionHalfFoldedTimeout">600</integer>
+
<!-- Indicates that the device supports having more than one internal display on at the same
time. Only applicable to devices with more than one internal display. If this option is
set to false, DisplayManager will make additional effort to ensure no more than 1 internal
@@ -5678,8 +5682,8 @@
restricted level.
-->
<array name="config_bg_current_drain_threshold_to_bg_restricted">
- <item>10.0</item> <!-- regular device -->
- <item>20.0</item> <!-- low ram device -->
+ <item>4.0</item> <!-- regular device -->
+ <item>8.0</item> <!-- low ram device -->
</array>
<!-- The background current drain monitoring window size. -->
@@ -5740,6 +5744,12 @@
-->
<bool name="config_bg_prompt_fgs_with_noti_to_bg_restricted">false</bool>
+ <!-- The behavior when the system detects it's abusive, should the system prompt the user
+ to put it into the bg restricted level.
+ True - we'll show the prompt to user, False - we'll not show it.
+ -->
+ <bool name="config_bg_prompt_abusive_apps_to_bg_restricted">false</bool>
+
<!-- The types of state where we'll exempt its battery usage during that state.
The state here must be one or a combination of STATE_TYPE_* in BaseAppStateTracker.
-->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a9b95da..3334822 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3957,6 +3957,7 @@
<java-symbol type="bool" name="config_supportsConcurrentInternalDisplays" />
<java-symbol type="bool" name="config_unfoldTransitionEnabled" />
<java-symbol type="bool" name="config_unfoldTransitionHingeAngle" />
+ <java-symbol type="integer" name="config_unfoldTransitionHalfFoldedTimeout" />
<java-symbol type="array" name="config_perDeviceStateRotationLockDefaults" />
@@ -4764,6 +4765,7 @@
<java-symbol type="integer" name="config_bg_current_drain_media_playback_min_duration" />
<java-symbol type="integer" name="config_bg_current_drain_location_min_duration" />
<java-symbol type="bool" name="config_bg_prompt_fgs_with_noti_to_bg_restricted" />
+ <java-symbol type="bool" name="config_bg_prompt_abusive_apps_to_bg_restricted" />
<java-symbol type="integer" name="config_bg_current_drain_exempted_types" />
<java-symbol type="bool" name="config_bg_current_drain_high_threshold_by_bg_location" />
<java-symbol type="drawable" name="ic_swap_horiz" />
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index a5da442..f9f3b4c 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -17,6 +17,30 @@
package android.app;
import static android.app.Notification.Builder.ensureColorSpanContrast;
+import static android.app.Notification.CarExtender.UnreadConversation.KEY_ON_READ;
+import static android.app.Notification.CarExtender.UnreadConversation.KEY_ON_REPLY;
+import static android.app.Notification.CarExtender.UnreadConversation.KEY_REMOTE_INPUT;
+import static android.app.Notification.EXTRA_ANSWER_INTENT;
+import static android.app.Notification.EXTRA_BUILDER_APPLICATION_INFO;
+import static android.app.Notification.EXTRA_CALL_PERSON;
+import static android.app.Notification.EXTRA_CONVERSATION_ICON;
+import static android.app.Notification.EXTRA_DECLINE_INTENT;
+import static android.app.Notification.EXTRA_HANG_UP_INTENT;
+import static android.app.Notification.EXTRA_LARGE_ICON;
+import static android.app.Notification.EXTRA_LARGE_ICON_BIG;
+import static android.app.Notification.EXTRA_MEDIA_REMOTE_INTENT;
+import static android.app.Notification.EXTRA_MEDIA_SESSION;
+import static android.app.Notification.EXTRA_MESSAGING_PERSON;
+import static android.app.Notification.EXTRA_PICTURE;
+import static android.app.Notification.EXTRA_PICTURE_ICON;
+import static android.app.Notification.MessagingStyle.Message.KEY_DATA_URI;
+import static android.app.Notification.MessagingStyle.Message.KEY_SENDER_PERSON;
+import static android.app.Notification.MessagingStyle.Message.KEY_TEXT;
+import static android.app.Notification.MessagingStyle.Message.KEY_TIMESTAMP;
+import static android.app.Notification.TvExtender.EXTRA_CONTENT_INTENT;
+import static android.app.Notification.TvExtender.EXTRA_DELETE_INTENT;
+import static android.app.Notification.WearableExtender.KEY_BACKGROUND;
+import static android.app.Notification.WearableExtender.KEY_DISPLAY_INTENT;
import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
import static com.android.internal.util.ContrastColorUtilTest.assertContrastIsAtLeast;
@@ -32,6 +56,7 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.spy;
import android.annotation.Nullable;
import android.content.Context;
@@ -43,6 +68,7 @@
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.drawable.Icon;
+import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
@@ -170,7 +196,7 @@
assertNotSame(q.getLargeIcon(), n.getLargeIcon());
assertTrue(q.getLargeIcon().getBitmap().sameAs(n.getLargeIcon().getBitmap()));
- assertSame(q.getLargeIcon(), q.extras.getParcelable(Notification.EXTRA_LARGE_ICON));
+ assertSame(q.getLargeIcon(), q.extras.getParcelable(EXTRA_LARGE_ICON));
}
@Test
@@ -179,12 +205,12 @@
mContext.getResources(), com.android.frameworks.coretests.R.drawable.test128x96));
Notification n = new Notification.Builder(mContext).build();
- n.extras.putParcelable(Notification.EXTRA_LARGE_ICON, originalIcon);
+ n.extras.putParcelable(EXTRA_LARGE_ICON, originalIcon);
assertSame(n.getLargeIcon(), null);
Notification q = writeAndReadParcelable(n);
assertSame(q.getLargeIcon(), null);
- assertTrue(((Icon) q.extras.getParcelable(Notification.EXTRA_LARGE_ICON)).getBitmap()
+ assertTrue(((Icon) q.extras.getParcelable(EXTRA_LARGE_ICON)).getBitmap()
.sameAs(originalIcon.getBitmap()));
}
@@ -641,7 +667,7 @@
public void testIsMediaNotification_invalidSession_returnsFalse() {
// Extra was set manually to an invalid type
Bundle extras = new Bundle();
- extras.putParcelable(Notification.EXTRA_MEDIA_SESSION, new Intent());
+ extras.putParcelable(EXTRA_MEDIA_SESSION, new Intent());
Notification.MediaStyle mediaStyle = new Notification.MediaStyle();
Notification notification = new Notification.Builder(mContext, "test id")
.setStyle(mediaStyle)
@@ -650,6 +676,7 @@
assertFalse(notification.isMediaNotification());
}
+ @Test
public void validateColorizedPaletteForColor(int rawColor) {
Notification.Colors cDay = new Notification.Colors();
Notification.Colors cNight = new Notification.Colors();
@@ -681,6 +708,174 @@
}
}
+ @Test
+ public void testVisitUris_invalidExtra_noCrash() {
+ Notification n = new Notification.Builder(mContext, "test")
+ .setSmallIcon(0)
+ .build();
+ Bundle fakeTypes = new Bundle();
+ fakeTypes.putParcelable(EXTRA_LARGE_ICON_BIG, new Bundle());
+ fakeTypes.putParcelable(EXTRA_PICTURE_ICON, new Bundle());
+ fakeTypes.putParcelable(EXTRA_MESSAGING_PERSON, new Bundle());
+
+ Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
+ n.visitUris(visitor);
+
+ // no crash, good
+ }
+
+ @Test
+ public void testRecoverBuilder_invalidExtra_noCrash() {
+ Notification n = new Notification.Builder(mContext, "test")
+ .setSmallIcon(0)
+ .build();
+ Bundle fakeTypes = new Bundle();
+ fakeTypes.putParcelable(EXTRA_BUILDER_APPLICATION_INFO, new Bundle());
+
+ Notification.Builder.recoverBuilder(mContext, n);
+
+ // no crash, good
+ }
+
+ @Test
+ public void testIsMediaNotification_invalidExtra_noCrash() {
+ Notification n = new Notification.Builder(mContext, "test")
+ .setSmallIcon(0)
+ .setStyle(new Notification.MediaStyle())
+ .build();
+ Bundle fakeTypes = new Bundle();
+ fakeTypes.putParcelable(EXTRA_MEDIA_SESSION, new Bundle());
+
+ n.isMediaNotification();
+
+ // no crash, good
+ }
+
+ @Test
+ public void testRestoreFromExtras_BigText_invalidExtra_noCrash() {
+ Notification.Style style = new Notification.BigTextStyle();
+ Bundle fakeTypes = new Bundle();
+ fakeTypes.putParcelable(EXTRA_LARGE_ICON_BIG, new Bundle());
+
+ style.restoreFromExtras(fakeTypes);
+
+ // no crash, good
+ }
+
+ @Test
+ public void testRestoreFromExtras_Messaging_invalidExtra_noCrash() {
+ Notification.Style style = new Notification.MessagingStyle();
+ Bundle fakeTypes = new Bundle();
+ fakeTypes.putParcelable(EXTRA_MESSAGING_PERSON, new Bundle());
+ fakeTypes.putParcelable(EXTRA_CONVERSATION_ICON, new Bundle());
+
+ style.restoreFromExtras(fakeTypes);
+
+ // no crash, good
+ }
+
+ @Test
+ public void testRestoreFromExtras_Media_invalidExtra_noCrash() {
+ Notification.Style style = new Notification.MediaStyle();
+ Bundle fakeTypes = new Bundle();
+ fakeTypes.putParcelable(EXTRA_MEDIA_SESSION, new Bundle());
+ fakeTypes.putParcelable(EXTRA_MEDIA_REMOTE_INTENT, new Bundle());
+
+ style.restoreFromExtras(fakeTypes);
+
+ // no crash, good
+ }
+
+ @Test
+ public void testRestoreFromExtras_Call_invalidExtra_noCrash() {
+ Notification.Style style = new Notification.CallStyle();
+ Bundle fakeTypes = new Bundle();
+ fakeTypes.putParcelable(EXTRA_CALL_PERSON, new Bundle());
+ fakeTypes.putParcelable(EXTRA_ANSWER_INTENT, new Bundle());
+ fakeTypes.putParcelable(EXTRA_DECLINE_INTENT, new Bundle());
+ fakeTypes.putParcelable(EXTRA_HANG_UP_INTENT, new Bundle());
+
+ style.restoreFromExtras(fakeTypes);
+
+ // no crash, good
+ }
+
+ @Test
+ public void testGetPictureIcon_invalidExtra_noCrash() {
+ Bundle fakeTypes = new Bundle();
+ fakeTypes.putParcelable(EXTRA_PICTURE, new Bundle());
+ fakeTypes.putParcelable(EXTRA_PICTURE_ICON, new Bundle());
+
+ Notification.BigPictureStyle.getPictureIcon(fakeTypes);
+
+ // no crash, good
+ }
+
+ @Test
+ public void testWearableExtender_invalidExtra_noCrash() {
+ Notification n = new Notification.Builder(mContext, "test")
+ .setSmallIcon(0)
+ .setStyle(new Notification.MediaStyle())
+ .build();
+ Bundle fakeTypes = new Bundle();
+ fakeTypes.putParcelable(KEY_DISPLAY_INTENT, new Bundle());
+ fakeTypes.putParcelable(KEY_BACKGROUND, new Bundle());
+ Notification.WearableExtender extender = new Notification.WearableExtender(n);
+
+ // no crash, good
+ }
+
+ @Test
+ public void testCarExtender_invalidExtra_noCrash() {
+ Notification n = new Notification.Builder(mContext, "test")
+ .setSmallIcon(0)
+ .setStyle(new Notification.MediaStyle())
+ .build();
+ Bundle fakeTypes = new Bundle();
+ fakeTypes.putParcelable(EXTRA_LARGE_ICON, new Bundle());
+ Notification.CarExtender extender = new Notification.CarExtender(n);
+
+ // no crash, good
+ }
+
+ @Test
+ public void testTvExtender_invalidExtra_noCrash() {
+ Notification n = new Notification.Builder(mContext, "test")
+ .setSmallIcon(0)
+ .setStyle(new Notification.MediaStyle())
+ .build();
+ Bundle fakeTypes = new Bundle();
+ fakeTypes.putParcelable(EXTRA_CONTENT_INTENT, new Bundle());
+ fakeTypes.putParcelable(EXTRA_DELETE_INTENT, new Bundle());
+ Notification.TvExtender extender = new Notification.TvExtender(n);
+
+ // no crash, good
+ }
+
+ @Test
+ public void testGetUnreadConversationFromBundle_invalidExtra_noCrash() {
+ Bundle fakeTypes = new Bundle();
+ fakeTypes.putParcelable(KEY_ON_READ, new Bundle());
+ fakeTypes.putParcelable(KEY_ON_REPLY, new Bundle());
+ fakeTypes.putParcelable(KEY_REMOTE_INPUT, new Bundle());
+ Notification.CarExtender.UnreadConversation.getUnreadConversationFromBundle(fakeTypes);
+
+ // no crash, good
+ }
+
+ @Test
+ public void testGetMessageFromBundle_invalidExtra_noCrash() {
+ Bundle fakeTypes = new Bundle();
+ fakeTypes.putParcelable(KEY_SENDER_PERSON, new Bundle());
+ fakeTypes.putString(KEY_TEXT, "text");
+ fakeTypes.putLong(KEY_TIMESTAMP, 0);
+ fakeTypes.putParcelable(KEY_REMOTE_INPUT, new Bundle());
+ fakeTypes.putParcelable(KEY_DATA_URI, new Bundle());
+ Notification.MessagingStyle.Message.getMessageFromBundle(fakeTypes);
+
+ // no crash, good
+ }
+
private void assertValid(Notification.Colors c) {
// Assert that all colors are populated
assertThat(c.getBackgroundColor()).isNotEqualTo(Notification.COLOR_INVALID);
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 33a41ec..e20cef2 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -60,7 +60,8 @@
public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmentCallback,
ActivityEmbeddingComponent {
- private final SplitPresenter mPresenter;
+ @VisibleForTesting
+ final SplitPresenter mPresenter;
// Currently applied split configuration.
private final List<EmbeddingRule> mSplitRules = new ArrayList<>();
@@ -149,6 +150,7 @@
return;
}
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
final boolean wasInPip = isInPictureInPicture(container);
container.setInfo(taskFragmentInfo);
final boolean isInPip = isInPictureInPicture(container);
@@ -159,13 +161,13 @@
// Do not finish the dependents if the last activity is reparented to PiP.
// Instead, the original split should be cleanup, and the dependent may be expanded
// to fullscreen.
- cleanupForEnterPip(container);
- mPresenter.cleanupContainer(container, false /* shouldFinishDependent */);
+ cleanupForEnterPip(wct, container);
+ mPresenter.cleanupContainer(container, false /* shouldFinishDependent */, wct);
} else {
// Do not finish the dependents if this TaskFragment was cleared due to launching
// activity in the Task.
final boolean shouldFinishDependent = !taskFragmentInfo.isTaskClearedForReuse();
- mPresenter.cleanupContainer(container, shouldFinishDependent);
+ mPresenter.cleanupContainer(container, shouldFinishDependent, wct);
}
} else if (wasInPip && isInPip) {
// No update until exit PIP.
@@ -174,12 +176,13 @@
// Enter PIP.
// All overrides will be cleanup.
container.setLastRequestedBounds(null /* bounds */);
- cleanupForEnterPip(container);
+ cleanupForEnterPip(wct, container);
} else if (wasInPip) {
// Exit PIP.
// Updates the presentation of the container. Expand or launch placeholder if needed.
- mPresenter.updateContainer(container);
+ updateContainer(wct, container);
}
+ mPresenter.applyTransaction(wct);
updateCallbackIfNecessary();
}
@@ -188,7 +191,15 @@
final TaskFragmentContainer container = getContainer(taskFragmentInfo.getFragmentToken());
if (container != null) {
// Cleanup if the TaskFragment vanished is not requested by the organizer.
- mPresenter.cleanupContainer(container, true /* shouldFinishDependent */);
+ removeContainer(container);
+ // Make sure the top container is updated.
+ final TaskFragmentContainer newTopContainer = getTopActiveContainer(
+ container.getTaskId());
+ if (newTopContainer != null) {
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ updateContainer(wct, newTopContainer);
+ mPresenter.applyTransaction(wct);
+ }
updateCallbackIfNecessary();
}
cleanupTaskFragment(taskFragmentInfo.getFragmentToken());
@@ -452,7 +463,8 @@
}
/** Cleanups all the dependencies when the TaskFragment is entering PIP. */
- private void cleanupForEnterPip(@NonNull TaskFragmentContainer container) {
+ private void cleanupForEnterPip(@NonNull WindowContainerTransaction wct,
+ @NonNull TaskFragmentContainer container) {
final int taskId = container.getTaskId();
final TaskContainer taskContainer = mTaskContainers.get(taskId);
if (taskContainer == null) {
@@ -482,7 +494,9 @@
// If there is any TaskFragment split with the PIP TaskFragment, update their presentations
// since the split is dismissed.
// We don't want to close any of them even if they are dependencies of the PIP TaskFragment.
- mPresenter.updateContainers(containersToUpdate);
+ for (TaskFragmentContainer containerToUpdate : containersToUpdate) {
+ updateContainer(wct, containerToUpdate);
+ }
}
/**
@@ -502,6 +516,7 @@
// TaskFragment there.
taskContainer.mFinishedContainer.add(container.getTaskFragmentToken());
+ // Cleanup any split references.
final List<SplitContainer> containersToRemove = new ArrayList<>();
for (SplitContainer splitContainer : taskContainer.mSplitContainers) {
if (container.equals(splitContainer.getSecondaryContainer())
@@ -510,6 +525,11 @@
}
}
taskContainer.mSplitContainers.removeAll(containersToRemove);
+
+ // Cleanup any dependent references.
+ for (TaskFragmentContainer containerToUpdate : taskContainer.mContainers) {
+ containerToUpdate.removeContainerToFinishOnExit(container);
+ }
}
/**
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
index b55c16e..1b49585 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -36,7 +36,6 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import java.util.Collection;
import java.util.concurrent.Executor;
/**
@@ -73,16 +72,12 @@
}
/**
- * Updates the presentation of the provided containers.
+ * Deletes the specified container and all other associated and dependent containers in the same
+ * transaction.
*/
- void updateContainers(@NonNull Collection<TaskFragmentContainer> containers) {
- if (containers.isEmpty()) {
- return;
- }
+ void cleanupContainer(@NonNull TaskFragmentContainer container, boolean shouldFinishDependent) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
- for (TaskFragmentContainer container : containers) {
- mController.updateContainer(wct, container);
- }
+ cleanupContainer(container, shouldFinishDependent, wct);
applyTransaction(wct);
}
@@ -90,9 +85,8 @@
* Deletes the specified container and all other associated and dependent containers in the same
* transaction.
*/
- void cleanupContainer(@NonNull TaskFragmentContainer container, boolean shouldFinishDependent) {
- final WindowContainerTransaction wct = new WindowContainerTransaction();
-
+ void cleanupContainer(@NonNull TaskFragmentContainer container, boolean shouldFinishDependent,
+ @NonNull WindowContainerTransaction wct) {
container.finish(shouldFinishDependent, this, wct, mController);
final TaskFragmentContainer newTopContainer = mController.getTopActiveContainer(
@@ -100,8 +94,6 @@
if (newTopContainer != null) {
mController.updateContainer(wct, newTopContainer);
}
-
- applyTransaction(wct);
}
/**
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
index 20c929b..871f545 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -257,7 +257,8 @@
// Finish dependent containers
for (TaskFragmentContainer container : mContainersToFinishOnExit) {
- if (controller.shouldRetainAssociatedContainer(this, container)) {
+ if (container.mIsFinished
+ || controller.shouldRetainAssociatedContainer(this, container)) {
continue;
}
container.finish(true /* shouldFinishDependent */, presenter,
@@ -267,18 +268,13 @@
// Finish associated activities
for (Activity activity : mActivitiesToFinishOnExit) {
- if (controller.shouldRetainAssociatedActivity(this, activity)) {
+ if (activity.isFinishing()
+ || controller.shouldRetainAssociatedActivity(this, activity)) {
continue;
}
activity.finish();
}
mActivitiesToFinishOnExit.clear();
-
- // Finish activities that were being re-parented to this container.
- for (Activity activity : mPendingAppearedActivities) {
- activity.finish();
- }
- mPendingAppearedActivities.clear();
}
boolean isFinished() {
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
index a26a4b6..72519dc 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
@@ -17,13 +17,20 @@
package androidx.window.extensions.embedding;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.google.common.truth.Truth.assertWithMessage;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.content.res.Resources;
import android.platform.test.annotations.Presubmit;
+import android.window.TaskFragmentInfo;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -32,12 +39,14 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
/**
* Test class for {@link SplitController}.
*
* Build/Install/Run:
- * atest WMJetpackUnitTests:SplitController
+ * atest WMJetpackUnitTests:SplitControllerTest
*/
@Presubmit
@SmallTest
@@ -45,12 +54,24 @@
public class SplitControllerTest {
private static final int TASK_ID = 10;
+ @Mock
+ private Activity mActivity;
+ @Mock
+ private Resources mActivityResources;
+ @Mock
+ private TaskFragmentInfo mInfo;
private SplitController mSplitController;
+ private SplitPresenter mSplitPresenter;
@Before
public void setUp() {
+ MockitoAnnotations.initMocks(this);
mSplitController = new SplitController();
+ mSplitPresenter = mSplitController.mPresenter;
spyOn(mSplitController);
+ spyOn(mSplitPresenter);
+ doReturn(mActivityResources).when(mActivity).getResources();
+ doReturn(new Configuration()).when(mActivityResources).getConfiguration();
}
@Test
@@ -83,4 +104,17 @@
assertWithMessage("Must return null because tf1 has no running activity.")
.that(mSplitController.getTopActiveContainer(TASK_ID)).isNull();
}
+
+ @Test
+ public void testOnTaskFragmentVanished() {
+ final TaskFragmentContainer tf = mSplitController.newContainer(mActivity, TASK_ID);
+ doReturn(tf.getTaskFragmentToken()).when(mInfo).getFragmentToken();
+
+ // The TaskFragment has been removed in the server, we only need to cleanup the reference.
+ mSplitController.onTaskFragmentVanished(mInfo);
+
+ verify(mSplitPresenter, never()).deleteTaskFragment(any(), any());
+ verify(mSplitController).removeContainer(tf);
+ verify(mActivity, never()).finish();
+ }
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
new file mode 100644
index 0000000..97896c2
--- /dev/null
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2022 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 androidx.window.extensions.embedding;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+
+import android.app.Activity;
+import android.platform.test.annotations.Presubmit;
+import android.window.TaskFragmentInfo;
+import android.window.WindowContainerTransaction;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+
+/**
+ * Test class for {@link TaskFragmentContainer}.
+ *
+ * Build/Install/Run:
+ * atest WMJetpackUnitTests:TaskFragmentContainerTest
+ */
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TaskFragmentContainerTest {
+ private static final int TASK_ID = 10;
+
+ @Mock
+ private SplitPresenter mPresenter;
+ @Mock
+ private SplitController mController;
+ @Mock
+ private Activity mActivity;
+ @Mock
+ private TaskFragmentInfo mInfo;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void testFinish() {
+ final TaskFragmentContainer container = new TaskFragmentContainer(mActivity, TASK_ID);
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+
+ // Only remove the activity, but not clear the reference until appeared.
+ container.finish(true /* shouldFinishDependent */, mPresenter, wct, mController);
+
+ verify(mActivity).finish();
+ verify(mPresenter, never()).deleteTaskFragment(any(), any());
+ verify(mController, never()).removeContainer(any());
+
+ // Calling twice should not finish activity again.
+ clearInvocations(mActivity);
+ container.finish(true /* shouldFinishDependent */, mPresenter, wct, mController);
+
+ verify(mActivity, never()).finish();
+ verify(mPresenter, never()).deleteTaskFragment(any(), any());
+ verify(mController, never()).removeContainer(any());
+
+ // Remove all references after the container has appeared in server.
+ doReturn(new ArrayList<>()).when(mInfo).getActivities();
+ container.setInfo(mInfo);
+ container.finish(true /* shouldFinishDependent */, mPresenter, wct, mController);
+
+ verify(mActivity, never()).finish();
+ verify(mPresenter).deleteTaskFragment(wct, container.getTaskFragmentToken());
+ verify(mController).removeContainer(container);
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 42ac195..cfd0624 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -301,7 +301,8 @@
int backType = mBackNavigationInfo.getType();
RemoteAnimationTarget animationTarget = mBackNavigationInfo.getDepartingAnimationTarget();
- BackEvent backEvent = new BackEvent(0, 0, progress, swipeEdge, animationTarget);
+ BackEvent backEvent = new BackEvent(
+ event.getX(), event.getY(), progress, swipeEdge, animationTarget);
IOnBackInvokedCallback targetCallback = null;
if (shouldDispatchToLauncher(backType)) {
targetCallback = mBackToLauncherCallback;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index b6fb828..5ef2413 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -385,7 +385,9 @@
mMainExecutor.execute(() -> {
int expandedId = INVALID_TASK_ID;
if (mStackView != null && mStackView.getExpandedBubble() != null
- && isStackExpanded() && !mStackView.isExpansionAnimating()) {
+ && isStackExpanded()
+ && !mStackView.isExpansionAnimating()
+ && !mStackView.isSwitchAnimating()) {
expandedId = mStackView.getExpandedBubble().getTaskId();
}
if (expandedId != INVALID_TASK_ID && expandedId != taskId) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index 6eb8d8a..7cfacbc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -329,6 +329,11 @@
: mBubbleSize;
}
+ /** Size of the visible (non-overlapping) part of the pointer. */
+ public int getPointerSize() {
+ return mPointerHeight - mPointerOverlap;
+ }
+
/** The maximum number of bubbles that can be displayed comfortably on screen. */
public int getMaxBubbles() {
return mMaxBubbles;
@@ -367,7 +372,7 @@
* padding is added.
*/
public int[] getExpandedViewContainerPadding(boolean onLeft, boolean isOverflow) {
- final int pointerTotalHeight = mPointerHeight - mPointerOverlap;
+ final int pointerTotalHeight = getPointerSize();
final int expandedViewLargeScreenInsetFurthestEdge =
getExpandedViewLargeScreenInsetFurthestEdge(isOverflow);
if (mIsLargeScreen) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 322c0bf..b7c5eb0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -1608,6 +1608,13 @@
}
/**
+ * Whether the stack of bubbles is animating a switch between bubbles.
+ */
+ public boolean isSwitchAnimating() {
+ return mIsBubbleSwitchAnimating;
+ }
+
+ /**
* The {@link Bubble} that is expanded, null if one does not exist.
*/
@VisibleForTesting
@@ -2467,6 +2474,10 @@
private void dismissBubbleIfExists(@Nullable BubbleViewProvider bubble) {
if (bubble != null && mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) {
+ if (mIsExpanded && mBubbleData.getBubbles().size() > 1) {
+ // If we have more than 1 bubble we will perform the switch animation
+ mIsBubbleSwitchAnimating = true;
+ }
mBubbleData.dismissBubbleWithKey(bubble.getKey(), Bubbles.DISMISS_USER_GESTURE);
}
}
@@ -2887,7 +2898,10 @@
PhysicsAnimator.getInstance(mAnimatingOutSurfaceContainer).cancel();
mAnimatingOutSurfaceContainer.setScaleX(1f);
mAnimatingOutSurfaceContainer.setScaleY(1f);
- mAnimatingOutSurfaceContainer.setTranslationX(mExpandedViewContainer.getPaddingLeft());
+ final float translationX = mPositioner.showBubblesVertically() && mStackOnLeftOrWillBe
+ ? mExpandedViewContainer.getPaddingLeft() + mPositioner.getPointerSize()
+ : mExpandedViewContainer.getPaddingLeft();
+ mAnimatingOutSurfaceContainer.setTranslationX(translationX);
mAnimatingOutSurfaceContainer.setTranslationY(0);
final int[] taskViewLocation =
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
index 003c559..4bb5805 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizer.java
@@ -40,7 +40,7 @@
import androidx.annotation.NonNull;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.policy.ForceShowNavigationBarSettingsObserver;
+import com.android.internal.policy.KidsModeSettingsObserver;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayInsetsController;
@@ -85,7 +85,7 @@
private int mDisplayWidth;
private int mDisplayHeight;
- private ForceShowNavigationBarSettingsObserver mForceShowNavigationBarSettingsObserver;
+ private KidsModeSettingsObserver mKidsModeSettingsObserver;
private boolean mEnabled;
DisplayController.OnDisplaysChangedListener mOnDisplaysChangedListener =
@@ -138,14 +138,14 @@
DisplayController displayController,
DisplayInsetsController displayInsetsController,
Optional<RecentTasksController> recentTasks,
- ForceShowNavigationBarSettingsObserver forceShowNavigationBarSettingsObserver) {
+ KidsModeSettingsObserver kidsModeSettingsObserver) {
super(taskOrganizerController, mainExecutor, context, /* compatUI= */ null, recentTasks);
mContext = context;
mMainHandler = mainHandler;
mSyncQueue = syncTransactionQueue;
mDisplayController = displayController;
mDisplayInsetsController = displayInsetsController;
- mForceShowNavigationBarSettingsObserver = forceShowNavigationBarSettingsObserver;
+ mKidsModeSettingsObserver = kidsModeSettingsObserver;
}
public KidsModeTaskOrganizer(
@@ -169,13 +169,13 @@
*/
public void initialize(StartingWindowController startingWindowController) {
initStartingWindow(startingWindowController);
- if (mForceShowNavigationBarSettingsObserver == null) {
- mForceShowNavigationBarSettingsObserver = new ForceShowNavigationBarSettingsObserver(
+ if (mKidsModeSettingsObserver == null) {
+ mKidsModeSettingsObserver = new KidsModeSettingsObserver(
mMainHandler, mContext);
}
- mForceShowNavigationBarSettingsObserver.setOnChangeRunnable(() -> updateKidsModeState());
+ mKidsModeSettingsObserver.setOnChangeRunnable(() -> updateKidsModeState());
updateKidsModeState();
- mForceShowNavigationBarSettingsObserver.register();
+ mKidsModeSettingsObserver.register();
}
@Override
@@ -211,7 +211,7 @@
@VisibleForTesting
void updateKidsModeState() {
- final boolean enabled = mForceShowNavigationBarSettingsObserver.isEnabled();
+ final boolean enabled = mKidsModeSettingsObserver.isEnabled();
if (mEnabled == enabled) {
return;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index b6635f3..9dc861c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -924,6 +924,7 @@
removeContentOverlay(mSwipePipToHomeOverlay, null /* callback */);
mSwipePipToHomeOverlay = null;
}
+ resetShadowRadius();
mPipTransitionState.setInSwipePipToHomeTransition(false);
mPictureInPictureParams = null;
mPipTransitionState.setTransitionState(PipTransitionState.UNDEFINED);
@@ -1569,13 +1570,28 @@
// Avoid double removal, which is fatal.
return;
}
- final SurfaceControl.Transaction tx =
- mSurfaceControlTransactionFactory.getTransaction();
+ final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
tx.remove(surface);
tx.apply();
if (callback != null) callback.run();
}
+ private void resetShadowRadius() {
+ if (mPipTransitionState.getTransitionState() == PipTransitionState.UNDEFINED) {
+ // mLeash is undefined when in PipTransitionState.UNDEFINED
+ return;
+ }
+ final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
+ tx.setShadowRadius(mLeash, 0f);
+ tx.apply();
+ }
+
+ @VisibleForTesting
+ public void setSurfaceControlTransactionFactory(
+ PipSurfaceTransactionHelper.SurfaceControlTransactionFactory factory) {
+ mSurfaceControlTransactionFactory = factory;
+ }
+
/**
* Dumps internal states.
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 10dfdc3..dd2634c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -414,7 +414,7 @@
}
RemoteAnimationTarget[] onGoingToRecentsLegacy(boolean cancel, RemoteAnimationTarget[] apps) {
- if (ENABLE_SHELL_TRANSITIONS || apps.length < 2) return null;
+ if (ENABLE_SHELL_TRANSITIONS || !isSplitScreenVisible()) return null;
// TODO(b/206487881): Integrate this with shell transition.
SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
if (mSplitTasksContainerLayer != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
index 75a999b..d89ddd2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
@@ -56,7 +56,6 @@
import android.util.Slog;
import android.view.ContextThemeWrapper;
import android.view.SurfaceControl;
-import android.view.View;
import android.window.SplashScreenView;
import android.window.StartingWindowInfo;
import android.window.StartingWindowInfo.StartingWindowType;
@@ -543,22 +542,6 @@
mBrandingImageHeight);
}
final SplashScreenView splashScreenView = builder.build();
- if (mSuggestType != STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN) {
- splashScreenView.addOnAttachStateChangeListener(
- new View.OnAttachStateChangeListener() {
- @Override
- public void onViewAttachedToWindow(View v) {
- SplashScreenView.applySystemBarsContrastColor(
- v.getWindowInsetsController(),
- splashScreenView.getInitBackgroundColor());
- }
-
- @Override
- public void onViewDetachedFromWindow(View v) {
- }
- });
- }
-
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
return splashScreenView;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index 11f23e3..464ab1a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -50,6 +50,7 @@
import android.view.Display;
import android.view.SurfaceControlViewHost;
import android.view.View;
+import android.view.WindowInsetsController;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.widget.FrameLayout;
@@ -63,6 +64,7 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.util.ContrastColorUtil;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TransactionPool;
@@ -121,6 +123,9 @@
private StartingSurface.SysuiProxy mSysuiProxy;
private final StartingWindowRemovalInfo mTmpRemovalInfo = new StartingWindowRemovalInfo();
+ private static final int LIGHT_BARS_MASK =
+ WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS
+ | WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
/**
* The minimum duration during which the splash screen is shown when the splash screen icon is
* animated.
@@ -361,9 +366,27 @@
// the window before first round relayoutWindow, which will happen after insets
// animation.
mChoreographer.postCallback(CALLBACK_INSETS_ANIMATION, setViewSynchronized, null);
- // Block until we get the background color.
final StartingWindowRecord record = mStartingWindowRecords.get(taskId);
+ record.parseAppSystemBarColor(context);
+ // Block until we get the background color.
final SplashScreenView contentView = viewSupplier.get();
+ if (suggestType != STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN) {
+ contentView.addOnAttachStateChangeListener(
+ new View.OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ final int lightBarAppearance = ContrastColorUtil.isColorLight(
+ contentView.getInitBackgroundColor())
+ ? LIGHT_BARS_MASK : 0;
+ contentView.getWindowInsetsController().setSystemBarsAppearance(
+ lightBarAppearance, LIGHT_BARS_MASK);
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ }
+ });
+ }
record.mBGColor = contentView.getInitBackgroundColor();
} else {
// release the icon view host
@@ -613,6 +636,7 @@
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW,
"Removing splash screen window for task: %d", taskId);
if (record.mContentView != null) {
+ record.clearSystemBarColor();
if (immediately
|| record.mSuggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN) {
removeWindowInner(record.mDecorView, false);
@@ -670,6 +694,8 @@
private @StartingWindowType int mSuggestType;
private int mBGColor;
private final long mCreateTime;
+ private int mSystemBarAppearance;
+ private boolean mDrawsSystemBarBackgrounds;
StartingWindowRecord(IBinder appToken, View decorView,
TaskSnapshotWindow taskSnapshotWindow, @StartingWindowType int suggestType) {
@@ -690,5 +716,37 @@
mContentView = splashScreenView;
mSetSplashScreen = true;
}
+
+ private void parseAppSystemBarColor(Context context) {
+ final TypedArray a = context.obtainStyledAttributes(R.styleable.Window);
+ mDrawsSystemBarBackgrounds = a.getBoolean(
+ R.styleable.Window_windowDrawsSystemBarBackgrounds, false);
+ if (a.getBoolean(R.styleable.Window_windowLightStatusBar, false)) {
+ mSystemBarAppearance |= WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
+ }
+ if (a.getBoolean(R.styleable.Window_windowLightNavigationBar, false)) {
+ mSystemBarAppearance |= WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
+ }
+ a.recycle();
+ }
+
+ // Reset the system bar color which set by splash screen, make it align to the app.
+ private void clearSystemBarColor() {
+ if (mDecorView == null) {
+ return;
+ }
+ if (mDecorView.getLayoutParams() instanceof WindowManager.LayoutParams) {
+ final WindowManager.LayoutParams lp =
+ (WindowManager.LayoutParams) mDecorView.getLayoutParams();
+ if (mDrawsSystemBarBackgrounds) {
+ lp.flags |= WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+ } else {
+ lp.flags &= ~WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+ }
+ mDecorView.setLayoutParams(lp);
+ }
+ mDecorView.getWindowInsetsController().setSystemBarsAppearance(
+ mSystemBarAppearance, LIGHT_BARS_MASK);
+ }
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java
index ff6dfdb..5526d5b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/kidsmode/KidsModeTaskOrganizerTest.java
@@ -44,7 +44,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
-import com.android.internal.policy.ForceShowNavigationBarSettingsObserver;
+import com.android.internal.policy.KidsModeSettingsObserver;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.ShellExecutor;
@@ -72,7 +72,7 @@
@Mock private SurfaceControl mLeash;
@Mock private WindowContainerToken mToken;
@Mock private WindowContainerTransaction mTransaction;
- @Mock private ForceShowNavigationBarSettingsObserver mObserver;
+ @Mock private KidsModeSettingsObserver mObserver;
@Mock private StartingWindowController mStartingWindowController;
@Mock private DisplayInsetsController mDisplayInsetsController;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
index 8ef1df6..c685fdc 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipAnimationControllerTest.java
@@ -30,7 +30,6 @@
import static org.mockito.Mockito.verify;
import android.app.TaskInfo;
-import android.graphics.Matrix;
import android.graphics.Rect;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -104,7 +103,7 @@
final PipAnimationController.PipTransitionAnimator oldAnimator = mPipAnimationController
.getAnimator(mTaskInfo, mLeash, baseValue, startValue, endValue1, null,
TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_0);
- oldAnimator.setSurfaceControlTransactionFactory(DummySurfaceControlTx::new);
+ oldAnimator.setSurfaceControlTransactionFactory(PipDummySurfaceControlTx::new);
oldAnimator.start();
final PipAnimationController.PipTransitionAnimator newAnimator = mPipAnimationController
@@ -134,7 +133,7 @@
@Test
public void pipTransitionAnimator_rotatedEndValue() {
- final DummySurfaceControlTx tx = new DummySurfaceControlTx();
+ final PipDummySurfaceControlTx tx = new PipDummySurfaceControlTx();
final Rect startBounds = new Rect(200, 700, 400, 800);
final Rect endBounds = new Rect(0, 0, 500, 1000);
// Fullscreen to PiP.
@@ -184,7 +183,7 @@
final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
.getAnimator(mTaskInfo, mLeash, baseValue, startValue, endValue, null,
TRANSITION_DIRECTION_TO_PIP, 0, ROTATION_0);
- animator.setSurfaceControlTransactionFactory(DummySurfaceControlTx::new);
+ animator.setSurfaceControlTransactionFactory(PipDummySurfaceControlTx::new);
animator.setPipAnimationCallback(mPipAnimationCallback);
@@ -201,44 +200,4 @@
verify(mPipAnimationCallback).onPipAnimationEnd(eq(mTaskInfo),
any(SurfaceControl.Transaction.class), eq(animator));
}
-
- /**
- * A dummy {@link SurfaceControl.Transaction} class.
- * This is created as {@link Mock} does not support method chaining.
- */
- public static class DummySurfaceControlTx extends SurfaceControl.Transaction {
- @Override
- public SurfaceControl.Transaction setAlpha(SurfaceControl leash, float alpha) {
- return this;
- }
-
- @Override
- public SurfaceControl.Transaction setPosition(SurfaceControl leash, float x, float y) {
- return this;
- }
-
- @Override
- public SurfaceControl.Transaction setWindowCrop(SurfaceControl leash, int w, int h) {
- return this;
- }
-
- @Override
- public SurfaceControl.Transaction setCornerRadius(SurfaceControl leash, float radius) {
- return this;
- }
-
- @Override
- public SurfaceControl.Transaction setMatrix(SurfaceControl leash, Matrix matrix,
- float[] float9) {
- return this;
- }
-
- @Override
- public SurfaceControl.Transaction setFrameTimelineVsync(long frameTimelineVsyncId) {
- return this;
- }
-
- @Override
- public void apply() {}
- }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipDummySurfaceControlTx.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipDummySurfaceControlTx.java
new file mode 100644
index 0000000..ccf8f6e
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipDummySurfaceControlTx.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2022 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.wm.shell.pip;
+
+import android.graphics.Matrix;
+import android.view.SurfaceControl;
+
+/**
+ * A dummy {@link SurfaceControl.Transaction} class for testing purpose and supports
+ * method chaining.
+ */
+public class PipDummySurfaceControlTx extends SurfaceControl.Transaction {
+ @Override
+ public SurfaceControl.Transaction setAlpha(SurfaceControl leash, float alpha) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setPosition(SurfaceControl leash, float x, float y) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setWindowCrop(SurfaceControl leash, int w, int h) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setCornerRadius(SurfaceControl leash, float radius) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setShadowRadius(SurfaceControl leash, float radius) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setMatrix(SurfaceControl leash, Matrix matrix,
+ float[] float9) {
+ return this;
+ }
+
+ @Override
+ public SurfaceControl.Transaction setFrameTimelineVsync(long frameTimelineVsyncId) {
+ return this;
+ }
+
+ @Override
+ public void apply() {}
+}
+
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index 14d9fb9..def9ad2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
@@ -242,6 +242,7 @@
mPipBoundsState.setDisplayLayout(new DisplayLayout(info,
mContext.getResources(), true, true));
mSpiedPipTaskOrganizer.setOneShotAnimationType(PipAnimationController.ANIM_TYPE_ALPHA);
+ mSpiedPipTaskOrganizer.setSurfaceControlTransactionFactory(PipDummySurfaceControlTx::new);
doNothing().when(mSpiedPipTaskOrganizer).enterPipWithAlphaAnimation(any(), anyLong());
doNothing().when(mSpiedPipTaskOrganizer).scheduleAnimateResizePip(any(), anyInt(), any());
}
diff --git a/media/java/android/media/tv/tuner/filter/Filter.java b/media/java/android/media/tv/tuner/filter/Filter.java
index a3e731b..d0973f4 100644
--- a/media/java/android/media/tv/tuner/filter/Filter.java
+++ b/media/java/android/media/tv/tuner/filter/Filter.java
@@ -560,6 +560,11 @@
*/
@Override
public void close() {
+ synchronized (mCallbackLock) {
+ mCallback = null;
+ mExecutor = null;
+ }
+
synchronized (mLock) {
if (mIsClosed) {
return;
@@ -568,8 +573,6 @@
if (res != Tuner.RESULT_SUCCESS) {
TunerUtils.throwExceptionForResult(res, "Failed to close filter.");
} else {
- mCallback = null;
- mExecutor = null;
mIsStarted = false;
mIsClosed = true;
}
diff --git a/packages/SettingsLib/Utils/src/com/android/settingslib/utils/BuildCompatUtils.java b/packages/SettingsLib/Utils/src/com/android/settingslib/utils/BuildCompatUtils.java
index 88e2423..ddbc907 100644
--- a/packages/SettingsLib/Utils/src/com/android/settingslib/utils/BuildCompatUtils.java
+++ b/packages/SettingsLib/Utils/src/com/android/settingslib/utils/BuildCompatUtils.java
@@ -48,37 +48,13 @@
}
/**
- * Implementation of BuildCompat.isAtLeast*() suitable for use in Settings
- *
- * <p>This still should try using BuildCompat.isAtLeastR() as source of truth, but also checking
- * for VERSION_SDK_INT and VERSION.CODENAME in case when BuildCompat implementation returned
- * false. Note that both checks should be >= and not = to make sure that when Android version
- * increases (i.e., from R to S), this does not stop working.
- *
- * <p>Supported configurations:
- *
- * <ul>
- * <li>For current Android release: when new API is not finalized yet (CODENAME = "Tiramisu",
- * SDK_INT = 32)
- * <li>For current Android release: when new API is finalized (CODENAME = "REL", SDK_INT = 33)
- * <li>For next Android release (CODENAME = "U", SDK_INT = 34+)
- * </ul>
- *
- * <p>Note that Build.VERSION_CODES.S cannot be used here until final SDK is available, because
- * it is equal to Build.VERSION_CODES.CUR_DEVELOPMENT before API finalization.
+ * Implementation of BuildCompat.isAtLeastT() suitable for use in Settings
*
* @return Whether the current OS version is higher or equal to T.
*/
+ @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.TIRAMISU)
public static boolean isAtLeastT() {
- if (!isAtLeastS()) {
- return false;
- }
-
- return (VERSION.CODENAME.equals("REL") && VERSION.SDK_INT >= 33)
- || (VERSION.CODENAME.length() >= 1
- && VERSION.CODENAME.toUpperCase().charAt(0) >= 'T'
- && VERSION.CODENAME.toUpperCase().charAt(0) <= 'Z')
- || (Build.VERSION.CODENAME.equals("Tiramisu") && Build.VERSION.SDK_INT >= 32);
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU;
}
private BuildCompatUtils() {}
diff --git a/packages/SettingsLib/res/drawable/broadcast_dialog_btn_bg.xml b/packages/SettingsLib/res/drawable/broadcast_dialog_btn_bg.xml
new file mode 100644
index 0000000..5fd7ee29
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/broadcast_dialog_btn_bg.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="rectangle">
+ <solid android:color="?androidprv:attr/colorAccentPrimary" />
+ <corners android:radius="@dimen/broadcast_dialog_btn_radius" />
+</shape>
diff --git a/packages/SettingsLib/res/layout/broadcast_dialog.xml b/packages/SettingsLib/res/layout/broadcast_dialog.xml
new file mode 100644
index 0000000..ec69aa5
--- /dev/null
+++ b/packages/SettingsLib/res/layout/broadcast_dialog.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:id="@+id/dialog_bg"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/broadcast_dialog_margin"
+ android:orientation="vertical">
+
+ <ImageView
+ android:id="@+id/dialog_icon"
+ android:layout_width="@dimen/broadcast_dialog_icon_size"
+ android:layout_height="@dimen/broadcast_dialog_icon_size"
+ android:layout_marginTop="@dimen/broadcast_dialog_icon_margin_top"
+ android:layout_marginBottom="@dimen/broadcast_dialog_title_img_margin_top"
+ android:layout_gravity="center"
+ android:src="@drawable/settings_input_antenna"/>
+
+ <TextView
+ style="@style/BroadcastDialogTitleStyle"
+ android:id="@+id/dialog_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_gravity="center"/>
+
+ <TextView
+ style="@style/BroadcastDialogBodyStyle"
+ android:id="@+id/dialog_subtitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:layout_gravity="center"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/broadcast_dialog_margin"
+ android:layout_marginBottom="@dimen/broadcast_dialog_margin"
+ android:orientation="vertical">
+
+ <Button
+ android:layout_marginBottom="@dimen/broadcast_dialog_btn_margin_bottom"
+ android:id="@+id/positive_btn"
+ style="@style/BroadcastDialogButtonStyle"/>
+
+ <Button
+ android:layout_marginBottom="@dimen/broadcast_dialog_btn_margin_bottom"
+ android:id="@+id/negative_btn"
+ android:text="@string/bt_le_audio_broadcast_dialog_different_output"
+ style="@style/BroadcastDialogButtonStyle"/>
+
+ <Button
+ android:id="@+id/neutral_btn"
+ android:text="@android:string/cancel"
+ style="@style/BroadcastDialogButtonStyle"/>
+ </LinearLayout>
+
+ </LinearLayout>
+</FrameLayout>
diff --git a/packages/SettingsLib/res/layout/qrcode_scanner_fragment.xml b/packages/SettingsLib/res/layout/qrcode_scanner_fragment.xml
index e071f4c4..0a7fe09 100644
--- a/packages/SettingsLib/res/layout/qrcode_scanner_fragment.xml
+++ b/packages/SettingsLib/res/layout/qrcode_scanner_fragment.xml
@@ -92,6 +92,7 @@
android:layout_marginStart="?attr/sudMarginStart"
android:layout_marginEnd="?attr/sudMarginEnd"
android:gravity="center"
+ android:layout_gravity="center"
android:visibility="invisible"/>
</LinearLayout>
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index 8315e8b..cbc79d2 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -120,4 +120,18 @@
<dimen name="qrcode_preview_margin">40dp</dimen>
<dimen name="qrcode_preview_radius">30dp</dimen>
<dimen name="qrcode_icon_size">27dp</dimen>
+
+ <!-- Broadcast dialog -->
+ <dimen name="broadcast_dialog_title_img_margin_top">18dp</dimen>
+ <dimen name="broadcast_dialog_title_text_size">24sp</dimen>
+ <dimen name="broadcast_dialog_title_text_margin">16dp</dimen>
+ <dimen name="broadcast_dialog_title_text_margin_top">18dp</dimen>
+ <dimen name="broadcast_dialog_subtitle_text_size">14sp</dimen>
+ <dimen name="broadcast_dialog_icon_size">24dp</dimen>
+ <dimen name="broadcast_dialog_icon_margin_top">25dp</dimen>
+ <dimen name="broadcast_dialog_btn_radius">100dp</dimen>
+ <dimen name="broadcast_dialog_btn_margin_bottom">4dp</dimen>
+ <dimen name="broadcast_dialog_btn_text_size">16sp</dimen>
+ <dimen name="broadcast_dialog_btn_minHeight">44dp</dimen>
+ <dimen name="broadcast_dialog_margin">16dp</dimen>
</resources>
diff --git a/packages/SettingsLib/res/values/styles.xml b/packages/SettingsLib/res/values/styles.xml
index 28cd27b..3234515 100644
--- a/packages/SettingsLib/res/values/styles.xml
+++ b/packages/SettingsLib/res/values/styles.xml
@@ -39,4 +39,49 @@
<item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:textDirection">locale</item>
</style>
+
+ <style name="BroadcastDialogTitleStyle">
+ <item name="android:textAppearance">@style/TextAppearanceBroadcastDialogTitle</item>
+ <item name="android:layout_marginStart">@dimen/broadcast_dialog_title_text_margin</item>
+ <item name="android:layout_marginEnd">@dimen/broadcast_dialog_title_text_margin</item>
+ <item name="android:layout_marginTop">@dimen/broadcast_dialog_title_text_margin_top</item>
+ <item name="android:layout_marginBottom">18dp</item>
+ </style>
+
+ <style name="TextAppearanceBroadcastDialogTitle" parent="@android:TextAppearance.DeviceDefault.Headline">
+ <item name="android:textSize">@dimen/broadcast_dialog_title_text_size</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textDirection">locale</item>
+ <item name="android:ellipsize">end</item>
+ </style>
+
+ <style name="BroadcastDialogBodyStyle">
+ <item name="android:textAppearance">@style/TextAppearanceBroadcastDialogSubTitle</item>
+ <item name="android:layout_margin">@dimen/broadcast_dialog_title_text_margin</item>
+ </style>
+
+ <style name="TextAppearanceBroadcastDialogSubTitle" parent="@android:TextAppearance.DeviceDefault.Headline">
+ <item name="android:textSize">@dimen/broadcast_dialog_subtitle_text_size</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ <item name="android:textDirection">locale</item>
+ <item name="android:ellipsize">end</item>
+ </style>
+
+ <style name="BroadcastDialogButtonStyle">
+ <item name="android:textAppearance">@style/TextAppearanceBroadcastDialogButton</item>
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_gravity">center</item>
+ <item name="android:gravity">center</item>
+ <item name="android:stateListAnimator">@null</item>
+ <item name="android:elevation">0dp</item>
+ <item name="android:minHeight">@dimen/broadcast_dialog_btn_minHeight</item>
+ <item name="android:background">@drawable/broadcast_dialog_btn_bg</item>
+ </style>
+
+ <style name="TextAppearanceBroadcastDialogButton" parent="@android:TextAppearance.DeviceDefault.Headline">
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textSize">@dimen/broadcast_dialog_btn_text_size</item>
+ </style>
+
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/DeviceInfoUtils.java b/packages/SettingsLib/src/com/android/settingslib/DeviceInfoUtils.java
index 0f34023..f627bcb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/DeviceInfoUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/DeviceInfoUtils.java
@@ -36,7 +36,8 @@
import androidx.annotation.RequiresApi;
import androidx.annotation.VisibleForTesting;
-import androidx.core.os.BuildCompat;
+
+import com.android.settingslib.utils.BuildCompatUtils;
import java.io.BufferedReader;
import java.io.FileReader;
@@ -220,7 +221,7 @@
}
private static String getRawPhoneNumber(Context context, int subscriptionId) {
- if (BuildCompat.isAtLeastT()) {
+ if (BuildCompatUtils.isAtLeastT()) {
return getRawPhoneNumberFromT(context, subscriptionId);
} else {
final TelephonyManager telephonyManager = context.getSystemService(
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
index 3a4a8d2..284da73 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
@@ -31,10 +31,11 @@
import android.widget.TextView;
import androidx.annotation.RequiresApi;
-import androidx.core.os.BuildCompat;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
+import com.android.settingslib.utils.BuildCompatUtils;
+
/**
* Helper class for managing settings preferences that can be disabled
* by device admins via user restrictions.
@@ -105,7 +106,7 @@
if (mDisabledSummary) {
final TextView summaryView = (TextView) holder.findViewById(android.R.id.summary);
if (summaryView != null) {
- final CharSequence disabledText = BuildCompat.isAtLeastT()
+ final CharSequence disabledText = BuildCompatUtils.isAtLeastT()
? getDisabledByAdminUpdatableString()
: mContext.getString(R.string.disabled_by_admin_summary_text);
if (mDisabledByAdmin) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index aaa0114..feb4212 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -45,7 +45,6 @@
import androidx.annotation.RequiresApi;
import androidx.core.graphics.drawable.RoundedBitmapDrawable;
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
-import androidx.core.os.BuildCompat;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.UserIcons;
@@ -53,6 +52,7 @@
import com.android.launcher3.icons.IconFactory;
import com.android.settingslib.drawable.UserIconDrawable;
import com.android.settingslib.fuelgauge.BatteryStatus;
+import com.android.settingslib.utils.BuildCompatUtils;
import java.text.NumberFormat;
@@ -130,7 +130,7 @@
String name = info != null ? info.name : null;
if (info.isManagedProfile()) {
// We use predefined values for managed profiles
- return BuildCompat.isAtLeastT()
+ return BuildCompatUtils.isAtLeastT()
? getUpdatableManagedUserTitle(context)
: context.getString(R.string.managed_user_title);
} else if (info.isGuest()) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BroadcastDialog.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BroadcastDialog.java
new file mode 100644
index 0000000..cb4eba4
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BroadcastDialog.java
@@ -0,0 +1,66 @@
+/**
+ * Copyright (C) 2022 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.settingslib.bluetooth;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.android.settingslib.R;
+
+public class BroadcastDialog extends AlertDialog {
+
+ private static final String TAG = "BroadcastDialog";
+
+ private String mCurrentApp;
+ private String mSwitchApp;
+ private Context mContext;
+
+ public BroadcastDialog(Context context) {
+ super(context);
+ mContext = context;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+
+ View layout = View.inflate(mContext, R.layout.broadcast_dialog, null);
+ final Window window = getWindow();
+ window.setContentView(layout);
+ window.setWindowAnimations(R.style.Theme_AlertDialog_SettingsLib);
+
+ TextView title = layout.findViewById(R.id.dialog_title);
+ TextView subTitle = layout.findViewById(R.id.dialog_subtitle);
+ title.setText(mContext.getString(R.string.bt_le_audio_broadcast_dialog_title, mCurrentApp));
+ subTitle.setText(
+ mContext.getString(R.string.bt_le_audio_broadcast_dialog_sub_title, mSwitchApp));
+ Button positiveBtn = layout.findViewById(R.id.positive_btn);
+ Button negativeBtn = layout.findViewById(R.id.negative_btn);
+ Button neutralBtn = layout.findViewById(R.id.neutral_btn);
+ positiveBtn.setText(mContext.getString(
+ R.string.bt_le_audio_broadcast_dialog_switch_app, mSwitchApp), null);
+ neutralBtn.setOnClickListener((view) -> {
+ Log.d(TAG, "BroadcastDialog dismiss.");
+ dismiss();
+ });
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java b/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
index 91d7388..11fae24 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java
@@ -47,7 +47,8 @@
import androidx.annotation.RequiresApi;
import androidx.annotation.VisibleForTesting;
-import androidx.core.os.BuildCompat;
+
+import com.android.settingslib.utils.BuildCompatUtils;
/**
* Converts the user avatar icon to a circularly clipped one with an optional badge and frame
@@ -87,7 +88,7 @@
* @return drawable containing just the badge
*/
public static Drawable getManagedUserDrawable(Context context) {
- if (BuildCompat.isAtLeastT()) {
+ if (BuildCompatUtils.isAtLeastT()) {
return getUpdatableManagedUserDrawable(context);
} else {
return getDrawableForDisplayDensity(
@@ -226,7 +227,7 @@
}
private static Drawable getManagementBadge(Context context) {
- if (BuildCompat.isAtLeastT()) {
+ if (BuildCompatUtils.isAtLeastT()) {
return getUpdatableManagementBadge(context);
} else {
return getDrawableForDisplayDensity(
diff --git a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeScanModeActivity.java b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeScanModeActivity.java
index 9021fcb..15a910e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeScanModeActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeScanModeActivity.java
@@ -26,8 +26,8 @@
import androidx.fragment.app.FragmentTransaction;
-import com.android.settingslib.bluetooth.BluetoothBroadcastUtils;
import com.android.settingslib.R;
+import com.android.settingslib.bluetooth.BluetoothBroadcastUtils;
import com.android.settingslib.bluetooth.BluetoothUtils;
public class QrCodeScanModeActivity extends QrCodeScanModeBaseActivity {
diff --git a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeScanModeBaseActivity.java b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeScanModeBaseActivity.java
index 9aaec41..361fd5b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeScanModeBaseActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeScanModeBaseActivity.java
@@ -1,4 +1,4 @@
-/*
+/**
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,8 +21,8 @@
import androidx.fragment.app.FragmentManager;
-import com.android.settingslib.core.lifecycle.ObservableActivity;
import com.android.settingslib.R;
+import com.android.settingslib.core.lifecycle.ObservableActivity;
public abstract class QrCodeScanModeBaseActivity extends ObservableActivity {
diff --git a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeScanModeController.java b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeScanModeController.java
index d7640bb..153d2d2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeScanModeController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeScanModeController.java
@@ -1,4 +1,4 @@
-/*
+/**
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeScanModeFragment.java b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeScanModeFragment.java
index 81165aa..069b950 100644
--- a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeScanModeFragment.java
+++ b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrCodeScanModeFragment.java
@@ -1,4 +1,4 @@
-/*
+/**
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -35,9 +35,9 @@
import android.view.accessibility.AccessibilityEvent;
import android.widget.TextView;
+import com.android.settingslib.R;
import com.android.settingslib.bluetooth.BluetoothBroadcastUtils;
import com.android.settingslib.bluetooth.BluetoothUtils;
-import com.android.settingslib.R;
import com.android.settingslib.core.lifecycle.ObservableFragment;
import androidx.annotation.NonNull;
diff --git a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrDecorateView.java b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrDecorateView.java
index 7005d36..51cf59c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrDecorateView.java
+++ b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrDecorateView.java
@@ -1,4 +1,4 @@
-/*
+/**
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrYuvLuminanceSource.java b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrYuvLuminanceSource.java
index 421cf5c..33f0cdd 100644
--- a/packages/SettingsLib/src/com/android/settingslib/qrcode/QrYuvLuminanceSource.java
+++ b/packages/SettingsLib/src/com/android/settingslib/qrcode/QrYuvLuminanceSource.java
@@ -1,4 +1,4 @@
-/*
+/**
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEnterpriseRestrictionUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEnterpriseRestrictionUtils.java
index 6535665..d97c819 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEnterpriseRestrictionUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEnterpriseRestrictionUtils.java
@@ -18,7 +18,6 @@
import android.content.Context;
import android.os.Build;
-import android.os.Bundle;
import android.os.UserManager;
import android.util.Log;
@@ -37,13 +36,9 @@
* @return whether the device is permitted to use Wi-Fi Tethering
*/
public static boolean isWifiTetheringAllowed(Context context) {
- final UserManager userManager = context.getSystemService(UserManager.class);
- final Bundle restrictions = userManager.getUserRestrictions();
- if (isAtLeastT() && restrictions.getBoolean(UserManager.DISALLOW_WIFI_TETHERING)) {
- Log.i(TAG, "Wi-Fi Tethering isn't available due to user restriction.");
- return false;
- }
- return true;
+ if (!hasUserRestrictionFromT(context, UserManager.DISALLOW_WIFI_TETHERING)) return true;
+ Log.w(TAG, "Wi-Fi Tethering isn't available due to user restriction.");
+ return false;
}
/**
@@ -53,13 +48,9 @@
* @return whether the device is permitted to use Wi-Fi Direct
*/
public static boolean isWifiDirectAllowed(Context context) {
- final UserManager userManager = context.getSystemService(UserManager.class);
- final Bundle restrictions = userManager.getUserRestrictions();
- if (isAtLeastT() && restrictions.getBoolean(UserManager.DISALLOW_WIFI_DIRECT)) {
- Log.i(TAG, "Wi-Fi Direct isn't available due to user restriction.");
- return false;
- }
- return true;
+ if (!hasUserRestrictionFromT(context, UserManager.DISALLOW_WIFI_DIRECT)) return true;
+ Log.w(TAG, "Wi-Fi Direct isn't available due to user restriction.");
+ return false;
}
/**
@@ -69,13 +60,9 @@
* @return whether the device is permitted to add new Wi-Fi config
*/
public static boolean isAddWifiConfigAllowed(Context context) {
- final UserManager userManager = context.getSystemService(UserManager.class);
- final Bundle restrictions = userManager.getUserRestrictions();
- if (isAtLeastT() && restrictions.getBoolean(UserManager.DISALLOW_ADD_WIFI_CONFIG)) {
- Log.i(TAG, "Wi-Fi Add network isn't available due to user restriction.");
- return false;
- }
- return true;
+ if (!hasUserRestrictionFromT(context, UserManager.DISALLOW_ADD_WIFI_CONFIG)) return true;
+ Log.w(TAG, "Wi-Fi Add network isn't available due to user restriction.");
+ return false;
}
/**
@@ -98,7 +85,7 @@
return userManager.hasUserRestriction(restrictionKey);
}
- @ChecksSdkIntAtLeast(api=Build.VERSION_CODES.TIRAMISU)
+ @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.TIRAMISU)
private static boolean isAtLeastT() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU;
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEnterpriseRestrictionUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEnterpriseRestrictionUtilsTest.java
index e9326dd..af9e69a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEnterpriseRestrictionUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEnterpriseRestrictionUtilsTest.java
@@ -15,122 +15,91 @@
*/
package com.android.settingslib.wifi;
+import static android.os.UserManager.DISALLOW_ADD_WIFI_CONFIG;
import static android.os.UserManager.DISALLOW_CHANGE_WIFI_STATE;
+import static android.os.UserManager.DISALLOW_WIFI_DIRECT;
+import static android.os.UserManager.DISALLOW_WIFI_TETHERING;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.Build;
-import android.os.Bundle;
import android.os.UserManager;
import androidx.test.core.app.ApplicationProvider;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.util.ReflectionHelpers;
@RunWith(RobolectricTestRunner.class)
public class WifiEnterpriseRestrictionUtilsTest {
- private Context mContext;
+ static final String SDK_INT = "SDK_INT";
+ static final int VERSION_CODES_S = Build.VERSION_CODES.S;
+ static final int VERSION_CODES_T = Build.VERSION_CODES.TIRAMISU;
+
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+ @Spy
+ Context mContext = ApplicationProvider.getApplicationContext();
@Mock
private UserManager mUserManager;
- @Mock
- private Bundle mBundle;
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
- mContext = spy(ApplicationProvider.getApplicationContext());
when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
- when(mUserManager.getUserRestrictions()).thenReturn(mBundle);
- ReflectionHelpers.setStaticField(
- Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.TIRAMISU);
+ ReflectionHelpers.setStaticField(Build.VERSION.class, SDK_INT, VERSION_CODES_T);
}
@Test
- public void isWifiTetheringAllowed_setSDKForS_shouldReturnTrue() {
- ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.S);
- when(mBundle.getBoolean(UserManager.DISALLOW_WIFI_TETHERING)).thenReturn(true);
-
- assertThat(WifiEnterpriseRestrictionUtils.isWifiTetheringAllowed(mContext)).isTrue();
- }
-
- @Test
- public void isWifiTetheringAllowed_setSDKForTAndDisallowForRestriction_shouldReturnFalse() {
- ReflectionHelpers.setStaticField(
- Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.TIRAMISU);
- when(mBundle.getBoolean(UserManager.DISALLOW_WIFI_TETHERING)).thenReturn(true);
+ public void isWifiTetheringAllowed_hasDisallowRestriction_shouldReturnFalse() {
+ when(mUserManager.hasUserRestriction(DISALLOW_WIFI_TETHERING)).thenReturn(true);
assertThat(WifiEnterpriseRestrictionUtils.isWifiTetheringAllowed(mContext)).isFalse();
}
@Test
- public void isWifiTetheringAllowed_setSDKForTAndAllowForRestriction_shouldReturnTrue() {
- ReflectionHelpers.setStaticField(
- Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.TIRAMISU);
- when(mBundle.getBoolean(UserManager.DISALLOW_WIFI_TETHERING)).thenReturn(false);
+ public void isWifiTetheringAllowed_noDisallowRestriction_shouldReturnTrue() {
+ when(mUserManager.hasUserRestriction(DISALLOW_WIFI_TETHERING)).thenReturn(false);
assertThat(WifiEnterpriseRestrictionUtils.isWifiTetheringAllowed(mContext)).isTrue();
}
@Test
- public void isWifiDirectAllowed_setSDKForS_shouldReturnTrue() {
- ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.S);
- when(mBundle.getBoolean(UserManager.DISALLOW_WIFI_DIRECT)).thenReturn(true);
-
- assertThat(WifiEnterpriseRestrictionUtils.isWifiDirectAllowed(mContext)).isTrue();
- }
-
- @Test
- public void isWifiDirectAllowed_setSDKForTAndDisallowForRestriction_shouldReturnFalse() {
- ReflectionHelpers.setStaticField(
- Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.TIRAMISU);
- when(mBundle.getBoolean(UserManager.DISALLOW_WIFI_DIRECT)).thenReturn(true);
+ public void isWifiDirectAllowed_hasDisallowRestriction_shouldReturnFalse() {
+ when(mUserManager.hasUserRestriction(DISALLOW_WIFI_DIRECT)).thenReturn(true);
assertThat(WifiEnterpriseRestrictionUtils.isWifiDirectAllowed(mContext)).isFalse();
}
@Test
- public void isWifiDirectAllowed_setSDKForTAndAllowForRestriction_shouldReturnTrue() {
- ReflectionHelpers.setStaticField(
- Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.TIRAMISU);
- when(mBundle.getBoolean(UserManager.DISALLOW_WIFI_DIRECT)).thenReturn(false);
+ public void isWifiDirectAllowed_noDisallowRestriction_shouldReturnTrue() {
+ when(mUserManager.hasUserRestriction(DISALLOW_WIFI_DIRECT)).thenReturn(false);
assertThat(WifiEnterpriseRestrictionUtils.isWifiDirectAllowed(mContext)).isTrue();
}
@Test
- public void isAddWifiConfigAllowed_setSDKForS_shouldReturnTrue() {
- ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.S);
- when(mBundle.getBoolean(UserManager.DISALLOW_ADD_WIFI_CONFIG)).thenReturn(true);
-
- assertThat(WifiEnterpriseRestrictionUtils.isAddWifiConfigAllowed(mContext)).isTrue();
- }
-
- @Test
- public void isAddWifiConfigAllowed_setSDKForTAndDisallowForRestriction_shouldReturnFalse() {
- ReflectionHelpers.setStaticField(
- Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.TIRAMISU);
- when(mBundle.getBoolean(UserManager.DISALLOW_ADD_WIFI_CONFIG)).thenReturn(true);
+ public void isAddWifiConfigAllowed_hasDisallowRestriction_shouldReturnFalse() {
+ when(mUserManager.hasUserRestriction(DISALLOW_ADD_WIFI_CONFIG)).thenReturn(true);
assertThat(WifiEnterpriseRestrictionUtils.isAddWifiConfigAllowed(mContext)).isFalse();
}
@Test
- public void isAddWifiConfigAllowed_setSDKForTAndAllowForRestriction_shouldReturnTrue() {
- ReflectionHelpers.setStaticField(
- Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.TIRAMISU);
- when(mBundle.getBoolean(UserManager.DISALLOW_ADD_WIFI_CONFIG)).thenReturn(false);
+ public void isAddWifiConfigAllowed_noDisallowRestriction_shouldReturnTrue() {
+ when(mUserManager.hasUserRestriction(DISALLOW_ADD_WIFI_CONFIG)).thenReturn(false);
assertThat(WifiEnterpriseRestrictionUtils.isAddWifiConfigAllowed(mContext)).isTrue();
}
@@ -143,7 +112,7 @@
}
@Test
- public void isChangeWifiStateAllowed_hasNoDisallowRestriction_shouldReturnTrue() {
+ public void isChangeWifiStateAllowed_noDisallowRestriction_shouldReturnTrue() {
when(mUserManager.hasUserRestriction(DISALLOW_CHANGE_WIFI_STATE)).thenReturn(false);
assertThat(WifiEnterpriseRestrictionUtils.isChangeWifiStateAllowed(mContext)).isTrue();
@@ -151,7 +120,7 @@
@Test
public void hasUserRestrictionFromT_setSDKForS_shouldReturnTrue() {
- ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.S);
+ ReflectionHelpers.setStaticField(Build.VERSION.class, SDK_INT, VERSION_CODES_S);
assertThat(WifiEnterpriseRestrictionUtils.hasUserRestrictionFromT(mContext, "key"))
.isFalse();
@@ -159,8 +128,7 @@
@Test
public void hasUserRestrictionFromT_setSDKForT_shouldReturnHasUserRestriction() {
- ReflectionHelpers.setStaticField(
- Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.TIRAMISU);
+ ReflectionHelpers.setStaticField(Build.VERSION.class, SDK_INT, VERSION_CODES_T);
when(mUserManager.hasUserRestriction(anyString())).thenReturn(false);
assertThat(WifiEnterpriseRestrictionUtils.hasUserRestrictionFromT(mContext, "key"))
diff --git a/packages/SystemUI/docs/usb_audio.md b/packages/SystemUI/docs/usb_audio.md
new file mode 100644
index 0000000..66e2df9
--- /dev/null
+++ b/packages/SystemUI/docs/usb_audio.md
@@ -0,0 +1,30 @@
+# USB audio Permission and Confirmation warning dialog resource string id matrix table
+### go/support-usb-access-aoc-offload-feature
+
+ |---|------------|----------------|------------------|-----------------|--------------------|
+ | # | Permission |isUsbAudioDevice| hasAudioPlayback | hasAudioCapture | string resource ID |
+ |---|------------|----------------|------------------|-----------------|--------------------|
+ | 1 | TRUE | TRUE | TRUE | FALSE | usb_audio_device_
+ permission_prompt |
+ |---|------------|----------------|------------------|-----------------|--------------------|
+ | 2 | TRUE | TRUE | FALSE | TRUE | usb_audio_device_
+ permission_prompt |
+ |---|------------|----------------|------------------|-----------------|--------------------|
+ | 3 | TRUE | TRUE | TRUE | TRUE | usb_audio_device_
+ permission_prompt |
+ |---|------------|----------------|------------------|-----------------|--------------------|
+ | 4 | TRUE | FALSE | N/A | N/A | usb_device_
+ permission_prompt |
+ |---|------------|----------------|------------------|-----------------|--------------------|
+ | 5 | FALSE | TRUE | TRUE | FALSE | usb_audio_device_
+ permission_prompt |
+ |---|------------|----------------|------------------|-----------------|--------------------|
+ | 6 | FALSE | TRUE | FALSE | TRUE | usb_audio_device_
+ permission_prompt_warn
+ |---|------------|----------------|------------------|-----------------|--------------------|
+ | 7 | FALSE | TRUE | TRUE | TRUE | usb_audio_device_
+ permission_prompt_warn
+ |---|------------|----------------|------------------|-----------------|--------------------|
+ | 8 | FALSE | FALSE | N/A | N/A | usb_device_
+ permission_prompt |
+ |---|------------|----------------|------------------|-----------------|--------------------|
diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
index f72a8dc..5b96159 100644
--- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
+++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
@@ -198,20 +198,29 @@
android:clickable="false"
android:focusable="false">
- <FrameLayout
- android:layout_weight="1"
- android:orientation="vertical"
- android:clickable="false"
+ <LinearLayout
android:layout_width="wrap_content"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:gravity="start|center_vertical"
+ android:orientation="vertical"
+ android:clickable="false">
<TextView
android:id="@+id/wifi_toggle_title"
android:text="@string/turn_on_wifi"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:gravity="start|center_vertical"
android:textAppearance="@style/TextAppearance.InternetDialog"/>
- </FrameLayout>
+ <TextView
+ android:id="@+id/wifi_toggle_summary"
+ android:text="@string/wifitrackerlib_admin_restricted_network"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="start|center_vertical"
+ android:textAppearance="@style/TextAppearance.InternetDialog.Secondary"
+ android:visibility="gone"/>
+ </LinearLayout>
<FrameLayout
android:layout_width="@dimen/settingslib_switch_track_width"
diff --git a/packages/SystemUI/res/layout/media_output_list_item.xml b/packages/SystemUI/res/layout/media_output_list_item.xml
index d39b0d5..b85ea59 100644
--- a/packages/SystemUI/res/layout/media_output_list_item.xml
+++ b/packages/SystemUI/res/layout/media_output_list_item.xml
@@ -33,7 +33,7 @@
android:layout_height="match_parent"
android:background="@drawable/media_output_item_background"
android:layout_gravity="center_vertical|start">
- <com.android.systemui.media.dialog.MediaOutputSeekbar
+ <SeekBar
android:id="@+id/volume_seekbar"
android:splitTrack="false"
android:visibility="gone"
@@ -119,15 +119,24 @@
android:importantForAccessibility="no"
android:visibility="gone"/>
+ <LinearLayout
+ android:id="@+id/end_action_area"
+ android:visibility="gone"
+ android:orientation="vertical"
+ android:layout_width="48dp"
+ android:layout_height="64dp"
+ android:layout_gravity="right|center"
+ android:gravity="center_vertical">
<CheckBox
android:id="@+id/check_box"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="16dp"
- android:layout_gravity="right|center"
+ android:layout_gravity="right"
android:button="@drawable/ic_circle_check_box"
android:visibility="gone"
- android:clickable="false"
/>
+
+ </LinearLayout>
</FrameLayout>
</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/media_smartspace_recommendations.xml b/packages/SystemUI/res/layout/media_smartspace_recommendations.xml
index c3fc669..6611c59 100644
--- a/packages/SystemUI/res/layout/media_smartspace_recommendations.xml
+++ b/packages/SystemUI/res/layout/media_smartspace_recommendations.xml
@@ -22,163 +22,145 @@
android:id="@+id/media_recommendations"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingStart="@dimen/qs_media_padding"
- android:paddingEnd="@dimen/qs_media_padding"
android:clipChildren="false"
android:clipToPadding="false"
android:forceHasOverlappingRendering="false"
android:background="@drawable/qs_media_background"
android:theme="@style/MediaPlayer">
- <androidx.constraintlayout.widget.Guideline
- android:id="@+id/media_vertical_start_guideline"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- app:layout_constraintGuide_percent="0.25" />
-
- <androidx.constraintlayout.widget.Guideline
- android:id="@+id/media_horizontal_center_guideline"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- app:layout_constraintGuide_percent="0.5" />
+ <!-- This view just ensures the full media player is a certain height. -->
+ <View
+ android:id="@+id/sizing_view"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/qs_media_session_height_expanded" />
<com.android.internal.widget.CachingIconView
android:id="@+id/recommendation_card_icon"
- android:layout_width="@dimen/qs_media_icon_size"
- android:layout_height="@dimen/qs_media_icon_size"
- android:layout_marginTop="@dimen/qs_media_padding"
- android:src="@drawable/ic_headset"
- style="@style/MediaPlayer.AppIcon"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toStartOf="@id/media_vertical_start_guideline"
- app:layout_constraintHorizontal_bias="0"/>
-
- <TextView
- android:id="@+id/recommendation_card_text"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:maxLines="1"
- android:text="@string/controls_media_smartspace_rec_title"
- android:fontFamily="google-sans-medium"
- android:textDirection="locale"
- android:textSize="@dimen/qq_aa_media_rec_header_text_size"
- android:hyphenationFrequency="none"
- app:layout_constraintTop_toBottomOf="@id/recommendation_card_icon"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toStartOf="@id/media_vertical_start_guideline"
- app:layout_constraintHorizontal_bias="0"/>
-
- <View
- android:id="@+id/recommendation_gradient_view"
- android:layout_width="@dimen/qs_aa_media_gradient_bg_width"
- android:layout_height="0dp"
- android:clipToPadding="false"
- android:clipChildren="false"
- android:background="@drawable/qs_media_recommendation_bg_gradient"
- app:layout_constraintTop_toTopOf="@id/recommendation_card_text"
- app:layout_constraintBottom_toBottomOf="@id/recommendation_card_text"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toStartOf="@id/media_vertical_start_guideline"
- app:layout_constraintHorizontal_bias="1"/>
+ style="@style/MediaPlayer.Recommendation.AppIcon" />
<FrameLayout
android:id="@+id/media_cover1_container"
- android:layout_width="0dp"
- android:layout_height="@dimen/qs_aa_media_rec_album_size_collapsed"
- android:background="@drawable/qs_media_light_source">
+ style="@style/MediaPlayer.Recommendation.AlbumContainer"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toTopOf="@+id/media_title1"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/media_cover2_container"
+ android:layout_marginEnd="@dimen/qs_media_rec_album_side_margin"
+ app:layout_constraintHorizontal_chainStyle="packed"
+ app:layout_constraintHorizontal_bias="1.0"
+ app:layout_constraintVertical_bias="0.5"
+ >
<ImageView
android:id="@+id/media_cover1"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
android:adjustViewBounds="true"
android:background="@drawable/bg_smartspace_media_item"
- style="@style/MediaPlayer.Album"
+ style="@style/MediaPlayer.Recommendation.Album"
android:clipToOutline="true"
android:scaleType="centerCrop"/>
</FrameLayout>
+ <TextView
+ android:id="@+id/media_title1"
+ style="@style/MediaPlayer.Recommendation.Text.Title"
+ app:layout_constraintStart_toStartOf="@+id/media_cover1_container"
+ app:layout_constraintEnd_toEndOf="@+id/media_cover1_container"
+ app:layout_constraintTop_toBottomOf="@+id/media_cover1_container"
+ app:layout_constraintBottom_toTopOf="@+id/media_subtitle1"
+ />
+
+ <TextView
+ android:id="@+id/media_subtitle1"
+ style="@style/MediaPlayer.Recommendation.Text.Subtitle"
+ app:layout_constraintStart_toStartOf="@+id/media_cover1_container"
+ app:layout_constraintEnd_toEndOf="@+id/media_cover1_container"
+ app:layout_constraintTop_toBottomOf="@+id/media_title1"
+ app:layout_constraintBottom_toBottomOf="parent"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ />
+
<FrameLayout
android:id="@+id/media_cover2_container"
- android:layout_width="0dp"
- android:layout_height="@dimen/qs_aa_media_rec_album_size_collapsed"
- android:background="@drawable/qs_media_light_source">
+ style="@style/MediaPlayer.Recommendation.AlbumContainer"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/media_title2"
+ app:layout_constraintStart_toEndOf="@id/media_cover1_container"
+ app:layout_constraintEnd_toStartOf="@id/media_cover3_container"
+ android:layout_marginEnd="@dimen/qs_media_rec_album_side_margin"
+ app:layout_constraintVertical_bias="0.5"
+ >
<ImageView
android:id="@+id/media_cover2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:background="@drawable/bg_smartspace_media_item"
- style="@style/MediaPlayer.Album"
+ style="@style/MediaPlayer.Recommendation.Album"
android:clipToOutline="true"
android:scaleType="centerCrop"/>
</FrameLayout>
+ <TextView
+ android:id="@+id/media_title2"
+ style="@style/MediaPlayer.Recommendation.Text.Title"
+ app:layout_constraintStart_toStartOf="@+id/media_cover2_container"
+ app:layout_constraintEnd_toEndOf="@+id/media_cover2_container"
+ app:layout_constraintTop_toBottomOf="@+id/media_cover2_container"
+ app:layout_constraintBottom_toTopOf="@+id/media_subtitle2"
+ />
+
+ <TextView
+ android:id="@+id/media_subtitle2"
+ style="@style/MediaPlayer.Recommendation.Text.Subtitle"
+ app:layout_constraintStart_toStartOf="@+id/media_cover2_container"
+ app:layout_constraintEnd_toEndOf="@+id/media_cover2_container"
+ app:layout_constraintTop_toBottomOf="@+id/media_title2"
+ app:layout_constraintBottom_toBottomOf="parent"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ />
+
<FrameLayout
android:id="@+id/media_cover3_container"
- android:layout_width="0dp"
- android:layout_height="@dimen/qs_aa_media_rec_album_size_collapsed"
- android:background="@drawable/qs_media_light_source">
+ style="@style/MediaPlayer.Recommendation.AlbumContainer"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/media_title3"
+ app:layout_constraintStart_toEndOf="@id/media_cover2_container"
+ app:layout_constraintEnd_toEndOf="parent"
+ android:layout_marginEnd="@dimen/qs_media_padding"
+ app:layout_constraintVertical_bias="0.5"
+ >
<ImageView
android:id="@+id/media_cover3"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:background="@drawable/bg_smartspace_media_item"
- style="@style/MediaPlayer.Album"
+ style="@style/MediaPlayer.Recommendation.Album"
android:clipToOutline="true"
android:scaleType="centerCrop"/>
</FrameLayout>
- <FrameLayout
- android:id="@+id/media_cover4_container"
- android:layout_width="0dp"
- android:layout_height="@dimen/qs_aa_media_rec_album_size_collapsed"
- android:background="@drawable/qs_media_light_source">
- <ImageView
- android:id="@+id/media_cover4"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:adjustViewBounds="true"
- android:background="@drawable/bg_smartspace_media_item"
- style="@style/MediaPlayer.Album"
- android:clipToOutline="true"
- android:scaleType="centerCrop"/>
- </FrameLayout>
+ <TextView
+ android:id="@+id/media_title3"
+ style="@style/MediaPlayer.Recommendation.Text.Title"
+ app:layout_constraintStart_toStartOf="@+id/media_cover3_container"
+ app:layout_constraintEnd_toEndOf="@+id/media_cover3_container"
+ app:layout_constraintTop_toBottomOf="@+id/media_cover3_container"
+ app:layout_constraintBottom_toTopOf="@+id/media_subtitle3"
+ />
- <FrameLayout
- android:id="@+id/media_cover5_container"
- android:layout_width="0dp"
- android:layout_height="@dimen/qs_aa_media_rec_album_size_collapsed"
- android:background="@drawable/qs_media_light_source">
- <ImageView
- android:id="@+id/media_cover5"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:adjustViewBounds="true"
- android:background="@drawable/bg_smartspace_media_item"
- style="@style/MediaPlayer.Album"
- android:clipToOutline="true"
- android:scaleType="centerCrop"/>
- </FrameLayout>
-
- <FrameLayout
- android:id="@+id/media_cover6_container"
- android:layout_width="0dp"
- android:layout_height="@dimen/qs_aa_media_rec_album_size_collapsed"
- android:background="@drawable/qs_media_light_source">
- <ImageView
- android:id="@+id/media_cover6"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:adjustViewBounds="true"
- android:background="@drawable/bg_smartspace_media_item"
- style="@style/MediaPlayer.Album"
- android:clipToOutline="true"
- android:scaleType="centerCrop"/>
- </FrameLayout>
+ <TextView
+ android:id="@+id/media_subtitle3"
+ style="@style/MediaPlayer.Recommendation.Text.Subtitle"
+ app:layout_constraintStart_toStartOf="@+id/media_cover3_container"
+ app:layout_constraintEnd_toEndOf="@+id/media_cover3_container"
+ app:layout_constraintTop_toBottomOf="@+id/media_title3"
+ app:layout_constraintBottom_toBottomOf="parent"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ />
<!-- Long press menu -->
<TextView
@@ -273,4 +255,4 @@
android:text="@string/controls_media_dismiss_button"
/>
</FrameLayout>
-</com.android.systemui.util.animation.TransitionLayout>
\ No newline at end of file
+</com.android.systemui.util.animation.TransitionLayout>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 4725515..a0115e8 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -561,6 +561,9 @@
<!-- The height of the gap between adjacent notification sections. -->
<dimen name="notification_section_divider_height">@dimen/notification_side_paddings</dimen>
+ <!-- The height of the gap between adjacent notification sections on lockscreen. -->
+ <dimen name="notification_section_divider_height_lockscreen">4dp</dimen>
+
<!-- Size of the face pile shown on one-line (children of a group) conversation notifications -->
<dimen name="conversation_single_line_face_pile_size">24dp</dimen>
@@ -959,7 +962,6 @@
<dimen name="qs_media_album_radius">14dp</dimen>
<dimen name="qs_media_info_margin">12dp</dimen>
<dimen name="qs_media_info_spacing">8dp</dimen>
- <dimen name="qs_media_icon_size">20dp</dimen>
<dimen name="qs_media_icon_offset">4dp</dimen>
<dimen name="qs_center_guideline_padding">10dp</dimen>
<dimen name="qs_media_action_spacing">4dp</dimen>
@@ -980,12 +982,10 @@
<dimen name="qs_media_session_collapsed_guideline">144dp</dimen>
<!-- Size of Smartspace media recommendations cards in the QSPanel carousel -->
- <dimen name="qs_aa_media_rec_album_size_collapsed">72dp</dimen>
- <dimen name="qs_aa_media_rec_album_size_expanded">76dp</dimen>
- <dimen name="qs_aa_media_gradient_bg_width">32dp</dimen>
- <dimen name="qs_aa_media_rec_album_margin">8dp</dimen>
- <dimen name="qs_aa_media_rec_album_margin_vert">4dp</dimen>
- <dimen name="qq_aa_media_rec_header_text_size">16sp</dimen>
+ <dimen name="qs_media_rec_album_size">88dp</dimen>
+ <dimen name="qs_media_rec_album_side_margin">16dp</dimen>
+ <dimen name="qs_media_rec_album_bottom_margin">8dp</dimen>
+ <dimen name="qs_media_rec_icon_size">24dp</dimen>
<!-- Media tap-to-transfer chip for sender device -->
<dimen name="media_ttt_chip_outer_padding">16dp</dimen>
@@ -1368,7 +1368,7 @@
<dimen name="keyguard_unfold_translation_x">16dp</dimen>
- <dimen name="fgs_manager_min_width_minor">100%</dimen>
+ <dimen name="fgs_manager_list_top_spacing">12dp</dimen>
<!-- Dream overlay related dimensions -->
<dimen name="dream_overlay_status_bar_height">60dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 0f5115b..f7acda7e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2440,14 +2440,16 @@
<!-- Label for the entry point to open the dialog which shows currently running applications [CHAR LIMIT=NONE]-->
<plurals name="fgs_manager_footer_label">
- <item quantity="one"><xliff:g id="count" example="1">%s</xliff:g> active app</item>
- <item quantity="other"><xliff:g id="count" example="2">%s</xliff:g> active apps</item>
+ <item quantity="one"><xliff:g id="count" example="1">%s</xliff:g> app is active</item>
+ <item quantity="other"><xliff:g id="count" example="2">%s</xliff:g> apps are active</item>
</plurals>
<!-- Content description for a dot indicator in the running application indicating that there
is new information [CHAR LIMIT=NONE] -->
<string name="fgs_dot_content_description">New information</string>
<!-- Title for dialog listing applications currently running [CHAR LIMIT=NONE]-->
<string name="fgs_manager_dialog_title">Active apps</string>
+ <!-- Detailed message for dialog listing applications currently running [CHAR LIMIT=NONE]-->
+ <string name="fgs_manager_dialog_message">Even if you\u2019re not using these apps, they\u2019re still active and might affect battery life</string>
<!-- Label of the button to stop an app from running [CHAR LIMIT=12]-->
<string name="fgs_manager_app_item_stop_button_label">Stop</string>
<!-- Label of the button to stop an app from running but the app is already stopped and the button is disabled [CHAR LIMIT=12]-->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index d7799a7..827631b 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -653,16 +653,50 @@
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
- <style name="MediaPlayer.AppIcon">
+ <style name="MediaPlayer.Recommendation"/>
+
+ <style name="MediaPlayer.Recommendation.AppIcon">
<item name="android:background">@drawable/qs_media_icon_background</item>
<item name="android:backgroundTint">@color/media_player_solid_button_bg</item>
- <item name="android:padding">4dp</item>
+ <item name="android:layout_width">@dimen/qs_media_rec_icon_size</item>
+ <item name="android:layout_height">@dimen/qs_media_rec_icon_size</item>
+ <item name="layout_constraintTop_toTopOf">parent</item>
+ <item name="layout_constraintStart_toStartOf">parent</item>
+ <item name="android:layout_marginTop">@dimen/qs_media_padding</item>
+ <item name="android:layout_marginStart">@dimen/qs_media_padding</item>
+ <item name="android:src">@drawable/ic_headset</item>
</style>
- <style name="MediaPlayer.Album">
+ <style name="MediaPlayer.Recommendation.AlbumContainer">
+ <item name="android:layout_width">@dimen/qs_media_rec_album_size</item>
+ <item name="android:layout_height">@dimen/qs_media_rec_album_size</item>
+ <item name="android:background">@drawable/qs_media_light_source</item>
+ <item name="android:layout_marginTop">@dimen/qs_media_padding</item>
+ <item name="android:layout_marginBottom">@dimen/qs_media_rec_album_bottom_margin</item>
+ </style>
+
+ <style name="MediaPlayer.Recommendation.Album">
<item name="android:backgroundTint">@color/media_player_album_bg</item>
</style>
+ <style name="MediaPlayer.Recommendation.Text">
+ <item name="android:layout_width">@dimen/qs_media_rec_album_size</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:maxLines">1</item>
+ <item name="android:ellipsize">end</item>
+ <item name="android:textSize">14sp</item>
+ <item name="android:gravity">start</item>
+ </style>
+
+ <style name="MediaPlayer.Recommendation.Text.Title">
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ </style>
+
+ <style name="MediaPlayer.Recommendation.Text.Subtitle">
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ </style>
+
+
<!-- Used to style charging animation AVD animation -->
<style name="ChargingAnim" />
@@ -1085,6 +1119,7 @@
<style name="FgsManagerAppLabel" parent="TextAppearance.Dialog.Body">
<item name="android:textDirection">locale</item>
+ <item name="android:textStyle">bold</item>
</style>
<style name="FgsManagerAppDuration">
diff --git a/packages/SystemUI/res/xml/media_recommendation_collapsed.xml b/packages/SystemUI/res/xml/media_recommendation_collapsed.xml
index b6258d1..a6113473 100644
--- a/packages/SystemUI/res/xml/media_recommendation_collapsed.xml
+++ b/packages/SystemUI/res/xml/media_recommendation_collapsed.xml
@@ -16,91 +16,84 @@
-->
<ConstraintSet
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
+ xmlns:app="http://schemas.android.com/apk/res-auto" >
<Constraint
+ android:id="@+id/sizing_view"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/qs_media_session_height_collapsed"
+ />
+
+ <!-- Only the constraintBottom and marginBottom are different. The rest of the constraints are
+ the same as the constraints in media_smartspace_recommendations. But due to how
+ ConstraintSets work, all the constraints need to be in the same place.
+ Ditto for the other cover containers. -->
+ <Constraint
android:id="@+id/media_cover1_container"
- android:layout_width="0dp"
- android:layout_height="@dimen/qs_aa_media_rec_album_size_collapsed"
- app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_collapsed"
- app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
- android:layout_marginTop="@dimen/qs_media_padding"
android:layout_marginBottom="@dimen/qs_media_padding"
- android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin"
- app:layout_constraintStart_toEndOf="@id/media_vertical_start_guideline"
+ style="@style/MediaPlayer.Recommendation.AlbumContainer"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/media_cover2_container"
+ android:layout_marginEnd="@dimen/qs_media_rec_album_side_margin"
app:layout_constraintHorizontal_chainStyle="packed"
- app:layout_constraintHorizontal_bias="1"
- android:visibility="gone" />
+ app:layout_constraintHorizontal_bias="1.0"
+ app:layout_constraintVertical_bias="0.5"
+ />
+
+ <Constraint
+ android:id="@+id/media_title1"
+ android:visibility="gone"
+ />
+
+ <Constraint
+ android:id="@+id/media_subtitle1"
+ android:visibility="gone"
+ />
<Constraint
android:id="@+id/media_cover2_container"
- android:layout_width="0dp"
- android:layout_height="@dimen/qs_aa_media_rec_album_size_collapsed"
- app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_collapsed"
- android:layout_marginTop="@dimen/qs_media_padding"
- android:layout_marginBottom="@dimen/qs_media_padding"
- android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin"
- app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ style="@style/MediaPlayer.Recommendation.AlbumContainer"
+ app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@id/media_cover1_container"
app:layout_constraintEnd_toStartOf="@id/media_cover3_container"
- app:layout_constraintHorizontal_chainStyle="packed"
- app:layout_constraintHorizontal_bias="1"
- android:visibility="gone" />
+ android:layout_marginEnd="@dimen/qs_media_rec_album_side_margin"
+ app:layout_constraintVertical_bias="0.5"
+ />
+
+ <Constraint
+ android:id="@+id/media_title2"
+ android:visibility="gone"
+ />
+
+ <Constraint
+ android:id="@+id/media_subtitle2"
+ android:visibility="gone"
+ />
<Constraint
android:id="@+id/media_cover3_container"
- android:layout_width="0dp"
- android:layout_height="@dimen/qs_aa_media_rec_album_size_collapsed"
- app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_collapsed"
- android:layout_marginTop="@dimen/qs_media_padding"
- android:layout_marginBottom="@dimen/qs_media_padding"
- app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ style="@style/MediaPlayer.Recommendation.AlbumContainer"
+ app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@id/media_cover2_container"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintHorizontal_chainStyle="packed"
- app:layout_constraintHorizontal_bias="1"
- android:visibility="gone" />
+ android:layout_marginEnd="@dimen/qs_media_padding"
+ app:layout_constraintVertical_bias="0.5"
+ />
<Constraint
- android:id="@+id/media_cover4_container"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin"
- app:layout_constraintTop_toBottomOf="@+id/media_cover1_container"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toEndOf="@id/media_vertical_start_guideline"
- app:layout_constraintEnd_toStartOf="@id/media_cover5_container"
- app:layout_constraintHorizontal_chainStyle="packed"
- app:layout_constraintHorizontal_bias="1"
- android:visibility="gone" />
+ android:id="@+id/media_title3"
+ android:visibility="gone"
+ />
<Constraint
- android:id="@+id/media_cover5_container"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin"
- app:layout_constraintTop_toBottomOf="@+id/media_cover2_container"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toEndOf="@+id/media_cover4_container"
- app:layout_constraintEnd_toStartOf="@+id/media_cover6_container"
- app:layout_constraintHorizontal_chainStyle="packed"
- app:layout_constraintHorizontal_bias="1"
- android:visibility="gone" />
-
- <Constraint
- android:id="@+id/media_cover6_container"
- android:layout_width="0dp"
- android:layout_height="0dp"
- app:layout_constraintTop_toBottomOf="@id/media_cover3_container"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toEndOf="@id/media_cover5_container"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintHorizontal_chainStyle="packed"
- app:layout_constraintHorizontal_bias="1"
- android:visibility="gone" />
+ android:id="@+id/media_subtitle3"
+ android:visibility="gone"
+ />
</ConstraintSet>
diff --git a/packages/SystemUI/res/xml/media_recommendation_expanded.xml b/packages/SystemUI/res/xml/media_recommendation_expanded.xml
index 2fb3341..09ffebb 100644
--- a/packages/SystemUI/res/xml/media_recommendation_expanded.xml
+++ b/packages/SystemUI/res/xml/media_recommendation_expanded.xml
@@ -15,113 +15,12 @@
~ limitations under the License
-->
<ConstraintSet
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto">
+ xmlns:android="http://schemas.android.com/apk/res/android" >
<Constraint
- android:id="@+id/media_cover1_container"
- android:layout_width="0dp"
- android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
- app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded"
- android:layout_marginTop="@dimen/qs_media_padding"
- android:layout_marginBottom="@dimen/qs_aa_media_rec_album_margin_vert"
- android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toTopOf="@+id/media_horizontal_center_guideline"
- app:layout_constraintStart_toEndOf="@id/media_vertical_start_guideline"
- app:layout_constraintEnd_toStartOf="@id/media_cover2_container"
- app:layout_constraintHorizontal_chainStyle="packed"
- app:layout_constraintHorizontal_bias="1"
- app:layout_constraintVertical_chainStyle="packed"
- app:layout_constraintVertical_bias="0"
- android:visibility="gone" />
-
- <Constraint
- android:id="@+id/media_cover2_container"
- android:layout_width="0dp"
- android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
- app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded"
- android:layout_marginTop="@dimen/qs_media_padding"
- android:layout_marginBottom="@dimen/qs_aa_media_rec_album_margin_vert"
- android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toTopOf="@+id/media_horizontal_center_guideline"
- app:layout_constraintStart_toEndOf="@id/media_cover1_container"
- app:layout_constraintEnd_toStartOf="@id/media_cover3_container"
- app:layout_constraintHorizontal_chainStyle="packed"
- app:layout_constraintHorizontal_bias="1"
- app:layout_constraintVertical_chainStyle="packed"
- app:layout_constraintVertical_bias="0"
- android:visibility="gone" />
-
- <Constraint
- android:id="@+id/media_cover3_container"
- android:layout_width="0dp"
- android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
- app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded"
- android:layout_marginTop="@dimen/qs_media_padding"
- android:layout_marginBottom="@dimen/qs_aa_media_rec_album_margin_vert"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toTopOf="@+id/media_horizontal_center_guideline"
- app:layout_constraintStart_toEndOf="@id/media_cover2_container"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintHorizontal_chainStyle="packed"
- app:layout_constraintHorizontal_bias="1"
- app:layout_constraintVertical_chainStyle="packed"
- app:layout_constraintVertical_bias="0"
- android:visibility="gone" />
-
- <Constraint
- android:id="@+id/media_cover4_container"
- android:layout_width="0dp"
- android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
- app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded"
- android:layout_marginTop="@dimen/qs_aa_media_rec_album_margin_vert"
- android:layout_marginBottom="@dimen/qs_media_padding"
- android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin"
- app:layout_constraintTop_toBottomOf="@+id/media_horizontal_center_guideline"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toEndOf="@id/media_vertical_start_guideline"
- app:layout_constraintEnd_toStartOf="@id/media_cover5_container"
- app:layout_constraintHorizontal_chainStyle="packed"
- app:layout_constraintHorizontal_bias="1"
- app:layout_constraintVertical_chainStyle="packed"
- app:layout_constraintVertical_bias="1"
- android:visibility="gone" />
-
- <Constraint
- android:id="@+id/media_cover5_container"
- android:layout_width="0dp"
- android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
- app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded"
- android:layout_marginTop="@dimen/qs_aa_media_rec_album_margin_vert"
- android:layout_marginBottom="@dimen/qs_media_padding"
- android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin"
- app:layout_constraintTop_toBottomOf="@+id/media_horizontal_center_guideline"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toEndOf="@+id/media_cover4_container"
- app:layout_constraintEnd_toStartOf="@+id/media_cover6_container"
- app:layout_constraintHorizontal_chainStyle="packed"
- app:layout_constraintHorizontal_bias="1"
- app:layout_constraintVertical_chainStyle="packed"
- app:layout_constraintVertical_bias="1"
- android:visibility="gone" />
-
- <Constraint
- android:id="@+id/media_cover6_container"
- android:layout_width="0dp"
- android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
- app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded"
- android:layout_marginTop="@dimen/qs_aa_media_rec_album_margin_vert"
- android:layout_marginBottom="@dimen/qs_media_padding"
- app:layout_constraintTop_toBottomOf="@id/media_horizontal_center_guideline"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toEndOf="@id/media_cover5_container"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintHorizontal_chainStyle="packed"
- app:layout_constraintHorizontal_bias="1"
- app:layout_constraintVertical_chainStyle="packed"
- app:layout_constraintVertical_bias="1"
- android:visibility="gone" />
+ android:id="@+id/sizing_view"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/qs_media_session_height_expanded"
+ />
</ConstraintSet>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
index bb7a0a71..01f417f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/rotation/RotationButtonController.java
@@ -568,7 +568,7 @@
}
}
- private class TaskStackListenerImpl extends TaskStackChangeListener {
+ private class TaskStackListenerImpl implements TaskStackChangeListener {
// Invalidate any rotation suggestion on task change or activity orientation change
// Note: all callbacks happen on main thread
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
index c5d5439..f65d82a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
@@ -26,30 +26,30 @@
* An interface to track task stack changes. Classes should implement this instead of
* {@link android.app.ITaskStackListener} to reduce IPC calls from system services.
*/
-public abstract class TaskStackChangeListener {
+public interface TaskStackChangeListener {
// Binder thread callbacks
- public void onTaskStackChangedBackground() { }
+ default void onTaskStackChangedBackground() { }
// Main thread callbacks
- public void onTaskStackChanged() { }
- public void onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) { }
- public void onActivityPinned(String packageName, int userId, int taskId, int stackId) { }
- public void onActivityUnpinned() { }
- public void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
+ default void onTaskStackChanged() { }
+ default void onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) { }
+ default void onActivityPinned(String packageName, int userId, int taskId, int stackId) { }
+ default void onActivityUnpinned() { }
+ default void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
boolean clearedTask, boolean wasVisible) { }
- public void onActivityForcedResizable(String packageName, int taskId, int reason) { }
- public void onActivityDismissingDockedStack() { }
- public void onActivityLaunchOnSecondaryDisplayFailed() { }
+ default void onActivityForcedResizable(String packageName, int taskId, int reason) { }
+ default void onActivityDismissingDockedStack() { }
+ default void onActivityLaunchOnSecondaryDisplayFailed() { }
- public void onActivityLaunchOnSecondaryDisplayFailed(RunningTaskInfo taskInfo) {
+ default void onActivityLaunchOnSecondaryDisplayFailed(RunningTaskInfo taskInfo) {
onActivityLaunchOnSecondaryDisplayFailed();
}
/**
* @see #onActivityLaunchOnSecondaryDisplayRerouted(RunningTaskInfo taskInfo)
*/
- public void onActivityLaunchOnSecondaryDisplayRerouted() { }
+ default void onActivityLaunchOnSecondaryDisplayRerouted() { }
/**
* Called when an activity was requested to be launched on a secondary display but was rerouted
@@ -57,16 +57,16 @@
*
* @param taskInfo info about the Activity's task
*/
- public void onActivityLaunchOnSecondaryDisplayRerouted(RunningTaskInfo taskInfo) {
+ default void onActivityLaunchOnSecondaryDisplayRerouted(RunningTaskInfo taskInfo) {
onActivityLaunchOnSecondaryDisplayRerouted();
}
- public void onTaskProfileLocked(int taskId, int userId) { }
- public void onTaskCreated(int taskId, ComponentName componentName) { }
- public void onTaskRemoved(int taskId) { }
- public void onTaskMovedToFront(int taskId) { }
+ default void onTaskProfileLocked(int taskId, int userId) { }
+ default void onTaskCreated(int taskId, ComponentName componentName) { }
+ default void onTaskRemoved(int taskId) { }
+ default void onTaskMovedToFront(int taskId) { }
- public void onTaskMovedToFront(RunningTaskInfo taskInfo) {
+ default void onTaskMovedToFront(RunningTaskInfo taskInfo) {
onTaskMovedToFront(taskInfo.taskId);
}
@@ -74,13 +74,14 @@
* Called when a task’s description is changed due to an activity calling
* ActivityManagerService.setTaskDescription
*
- * @param taskInfo info about the task which changed, with {@link TaskInfo#taskDescription}
+ * @param taskInfo info about the task which changed, with
+ * {@link RunningTaskInfo#taskDescription}
*/
- public void onTaskDescriptionChanged(RunningTaskInfo taskInfo) { }
+ default void onTaskDescriptionChanged(RunningTaskInfo taskInfo) { }
- public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) { }
+ default void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) { }
- public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) { }
+ default void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) { }
/**
* Called when a task is reparented to a stack on a different display.
@@ -88,22 +89,22 @@
* @param taskId id of the task which was moved to a different display.
* @param newDisplayId id of the new display.
*/
- public void onTaskDisplayChanged(int taskId, int newDisplayId) { }
+ default void onTaskDisplayChanged(int taskId, int newDisplayId) { }
/**
* Called when any additions or deletions to the recent tasks list have been made.
*/
- public void onRecentTaskListUpdated() { }
+ default void onRecentTaskListUpdated() { }
/** @see ITaskStackListener#onRecentTaskListFrozenChanged(boolean) */
- public void onRecentTaskListFrozenChanged(boolean frozen) { }
+ default void onRecentTaskListFrozenChanged(boolean frozen) { }
/** @see ITaskStackListener#onActivityRotation(int)*/
- public void onActivityRotation(int displayId) { }
+ default void onActivityRotation(int displayId) { }
/**
* Called when the lock task mode changes. See ActivityManager#LOCK_TASK_MODE_* and
* LockTaskController.
*/
- public void onLockTaskModeChanged(int mode) { }
+ default void onLockTaskModeChanged(int mode) { }
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
index ed973d6..83b72e8 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
@@ -57,6 +57,15 @@
private val foldStateListener = FoldStateListener(context)
private val timeoutRunnable = TimeoutRunnable()
+ /**
+ * Time after which [FOLD_UPDATE_FINISH_HALF_OPEN] is emitted following a
+ * [FOLD_UPDATE_START_CLOSING] or [FOLD_UPDATE_START_OPENING] event, if an end state is not
+ * reached.
+ */
+ private val halfOpenedTimeoutMillis: Int =
+ context.resources.getInteger(
+ com.android.internal.R.integer.config_unfoldTransitionHalfFoldedTimeout)
+
private var isFolded = false
private var isUnfoldHandled = true
@@ -171,7 +180,7 @@
if (isTransitionInProgess) {
cancelTimeout()
}
- handler.postDelayed(timeoutRunnable, HALF_OPENED_TIMEOUT_MILLIS)
+ handler.postDelayed(timeoutRunnable, halfOpenedTimeoutMillis.toLong())
}
private fun cancelTimeout() {
@@ -222,12 +231,6 @@
private const val TAG = "DeviceFoldProvider"
private const val DEBUG = false
-/**
- * Time after which [FOLD_UPDATE_FINISH_HALF_OPEN] is emitted following a
- * [FOLD_UPDATE_START_CLOSING] or [FOLD_UPDATE_START_OPENING] event, if an end state is not reached.
- */
-@VisibleForTesting const val HALF_OPENED_TIMEOUT_MILLIS = 600L
-
/** Threshold after which we consider the device fully unfolded. */
@VisibleForTesting const val FULLY_OPEN_THRESHOLD_DEGREES = 15f
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt
index 5953611..db2b4ac 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt
@@ -63,7 +63,8 @@
val primaryUser: Boolean,
val scanningAllowedByStrongAuth: Boolean,
val secureCameraLaunched: Boolean,
- val switchingUser: Boolean
+ val switchingUser: Boolean,
+ val udfpsBouncerShowing: Boolean
) : KeyguardListenModel()
/**
* Verbose debug information associated with [KeyguardUpdateMonitor.shouldTriggerActiveUnlock].
@@ -73,6 +74,7 @@
override val userId: Int,
override val listening: Boolean,
// keep sorted
+ val awakeKeyguard: Boolean,
val authInterruptActive: Boolean,
val encryptedOrTimedOut: Boolean,
val fpLockout: Boolean,
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 5cf1c0b..c0ba51f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -702,6 +702,7 @@
}
public void reset() {
+ mViewMode.reset();
mDisappearAnimRunning = false;
}
@@ -800,9 +801,6 @@
mUserSwitcherViewGroup = mView.findViewById(R.id.keyguard_bouncer_user_switcher);
}
- Drawable userIcon = findUserIcon(KeyguardUpdateMonitor.getCurrentUser());
- ((ImageView) mView.findViewById(R.id.user_icon)).setImageDrawable(userIcon);
-
updateSecurityViewLocation();
mUserSwitcher = mView.findViewById(R.id.user_switcher_header);
@@ -815,6 +813,7 @@
mPopup.dismiss();
mPopup = null;
}
+ setupUserSwitcher();
}
private Drawable findUserIcon(int userId) {
@@ -860,6 +859,12 @@
private void setupUserSwitcher() {
final UserRecord currentUser = mUserSwitcherController.getCurrentUserRecord();
+ if (currentUser == null) {
+ Log.wtf(TAG, "Current user in user switcher is null.");
+ return;
+ }
+ Drawable userIcon = findUserIcon(currentUser.info.id);
+ ((ImageView) mView.findViewById(R.id.user_icon)).setImageDrawable(userIcon);
mUserSwitcher.setText(mUserSwitcherController.getCurrentUserName());
ViewGroup anchor = mView.findViewById(R.id.user_switcher_anchor);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 1a325d3..ce4aad8 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -219,6 +219,11 @@
mKeyguardSecurityCallback.userActivity();
showMessage(null, null);
}
+ if (mUpdateMonitor.isFaceEnrolled()
+ && mUpdateMonitor.mRequestActiveUnlockOnUnlockIntent) {
+ mUpdateMonitor.requestActiveUnlock("unlock-intent, reason=swipeUpOnBouncer",
+ true);
+ }
}
};
private ConfigurationController.ConfigurationListener mConfigurationListener =
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index f1bec81..a6feedb5 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -56,6 +56,7 @@
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.hardware.SensorPrivacyManager;
+import android.hardware.biometrics.BiometricFaceConstants;
import android.hardware.biometrics.BiometricFingerprintConstants;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricSourceType;
@@ -88,6 +89,7 @@
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
+import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -246,6 +248,12 @@
}
}
+ public final boolean mRequestActiveUnlockOnAssistant;
+ public final boolean mRequestActiveUnlockOnWakeup;
+ public final boolean mInitiateActiveUnlockOnWakeup;
+ public final boolean mRequestActiveUnlockOnUnlockIntent;
+ public final boolean mRequestActiveUnlockOnBioFail;
+
private final Context mContext;
private final boolean mIsPrimaryUser;
private final boolean mIsAutomotive;
@@ -281,6 +289,7 @@
private boolean mGoingToSleep;
private boolean mBouncerFullyShown;
private boolean mBouncerIsOrWillBeShowing;
+ private boolean mUdfpsBouncerShowing;
private boolean mAuthInterruptActive;
private boolean mNeedsSlowUnlockTransition;
private boolean mAssistantVisible;
@@ -451,10 +460,16 @@
}
}
- if (KeyguardUpdateMonitor.getCurrentUser() == userId && getUserHasTrust(userId)) {
+ if (KeyguardUpdateMonitor.getCurrentUser() == userId) {
CharSequence message = null;
- if (trustGrantedMessages != null && trustGrantedMessages.size() > 0) {
- message = trustGrantedMessages.get(0); // for now only shows the first in the list
+ final boolean userHasTrust = getUserHasTrust(userId);
+ if (userHasTrust && trustGrantedMessages != null) {
+ for (String msg : trustGrantedMessages) {
+ if (!TextUtils.isEmpty(msg)) {
+ message = msg;
+ break;
+ }
+ }
}
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
@@ -463,6 +478,7 @@
}
}
}
+
}
@Override
@@ -1354,8 +1370,8 @@
void setAssistantVisible(boolean assistantVisible) {
mAssistantVisible = assistantVisible;
updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
- if (mAssistantVisible) {
- requestActiveUnlock();
+ if (mAssistantVisible && mRequestActiveUnlockOnAssistant) {
+ requestActiveUnlock("assistant", false);
}
}
@@ -1502,11 +1518,11 @@
@Override
public void onAuthenticationFailed() {
+ if (mRequestActiveUnlockOnBioFail) {
+ requestActiveUnlock("biometric-failure, extra=fingerprintFailure",
+ true);
+ }
handleFingerprintAuthFailed();
-
- // TODO(b/225231929): Refactor as needed, add tests, etc.
- mTrustManager.reportUserRequestedUnlock(
- KeyguardUpdateMonitor.getCurrentUser(), true);
}
@Override
@@ -1564,6 +1580,15 @@
@Override
public void onAuthenticationFailed() {
+ if (shouldRequestActiveUnlockOnFaceError()) {
+ String reason =
+ mKeyguardBypassController.canBypass() ? "bypass"
+ : mUdfpsBouncerShowing ? "udfpsBouncer" :
+ mBouncerFullyShown ? "bouncer" : "udfpsFpDown";
+ requestActiveUnlock("biometric-failure"
+ + ", extra=faceFailure-" + reason, true);
+ }
+
handleFaceAuthFailed();
if (mKeyguardBypassController != null) {
mKeyguardBypassController.setUserHasDeviceEntryIntent(false);
@@ -1592,12 +1617,23 @@
if (mKeyguardBypassController != null) {
mKeyguardBypassController.setUserHasDeviceEntryIntent(false);
}
+ if (errMsgId == BiometricFaceConstants.FACE_ERROR_TIMEOUT
+ && shouldRequestActiveUnlockOnFaceError()) {
+ requestActiveUnlock("biometric-failure"
+ + ", extra=faceError-" + errMsgId, true);
+ }
}
@Override
public void onAuthenticationAcquired(int acquireInfo) {
handleFaceAcquired(acquireInfo);
}
+
+ private boolean shouldRequestActiveUnlockOnFaceError() {
+ return mRequestActiveUnlockOnBioFail
+ && (mKeyguardBypassController.canBypass() || mBouncerFullyShown
+ || mUdfpsBouncerShowing || mAuthController.isUdfpsFingerDown());
+ }
};
@VisibleForTesting
@@ -1713,7 +1749,11 @@
Trace.beginSection("KeyguardUpdateMonitor#handleStartedWakingUp");
Assert.isMainThread();
updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
- requestActiveUnlock();
+ if (mRequestActiveUnlockOnWakeup) {
+ requestActiveUnlock("wake-unlock");
+ } else if (mInitiateActiveUnlockOnWakeup) {
+ initiateActiveUnlock("wake-initiate");
+ }
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
@@ -1860,6 +1900,18 @@
dumpManager.registerDumpable(getClass().getName(), this);
mSensorPrivacyManager = context.getSystemService(SensorPrivacyManager.class);
+ // TODO, b/222459888: add official configurable names to Settings.java
+ mRequestActiveUnlockOnWakeup = Settings.Global.getInt(
+ mContext.getContentResolver(), "wake-unlock", 0) == 1;
+ mInitiateActiveUnlockOnWakeup = Settings.Global.getInt(
+ mContext.getContentResolver(), "wake-initiate", 1) == 1;
+ mRequestActiveUnlockOnUnlockIntent = Settings.Global.getInt(
+ mContext.getContentResolver(), "unlock-intent", 0) == 1;
+ mRequestActiveUnlockOnBioFail = Settings.Global.getInt(
+ mContext.getContentResolver(), "bio-fail", 0) == 1;
+ mRequestActiveUnlockOnAssistant = Settings.Global.getInt(
+ mContext.getContentResolver(), "assistant", 0) == 1;
+
mHandler = new Handler(mainLooper) {
@Override
public void handleMessage(Message msg) {
@@ -2194,7 +2246,7 @@
}
// don't start running fingerprint until they're registered
- if (!mAuthController.areAllAuthenticatorsRegistered()) {
+ if (!mAuthController.areAllFingerprintAuthenticatorsRegistered()) {
return;
}
final boolean shouldListenForFingerprint = shouldListenForFingerprint(isUdfpsSupported());
@@ -2240,7 +2292,11 @@
}
mAuthInterruptActive = active;
updateFaceListeningState(BIOMETRIC_ACTION_UPDATE);
- requestActiveUnlock();
+ if (mRequestActiveUnlockOnWakeup) {
+ requestActiveUnlock("wake-unlock, extra=onReach");
+ } else if (mInitiateActiveUnlockOnWakeup) {
+ initiateActiveUnlock("wake-initiate, extra=onReach");
+ }
}
/**
@@ -2290,25 +2346,69 @@
}
/**
- * Attempts to trigger active unlock.
+ * Initiates active unlock to get the unlock token ready.
*/
- public void requestActiveUnlock() {
+ public void initiateActiveUnlock(String reason) {
// If this message exists, FP has already authenticated, so wait until that is handled
if (mHandler.hasMessages(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE)) {
return;
}
if (shouldTriggerActiveUnlock()) {
- // TODO(b/225231929): Refactor surrounding code to reflect calling of new method
+ if (DEBUG) {
+ Log.d("ActiveUnlock", "initiate active unlock triggerReason=" + reason);
+ }
mTrustManager.reportUserMayRequestUnlock(KeyguardUpdateMonitor.getCurrentUser());
}
}
+ /**
+ * Attempts to trigger active unlock from trust agent.
+ */
+ public void requestActiveUnlock(String reason, boolean dismissKeyguard) {
+ // If this message exists, FP has already authenticated, so wait until that is handled
+ if (mHandler.hasMessages(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE)) {
+ return;
+ }
+
+ if (shouldTriggerActiveUnlock()) {
+ if (DEBUG) {
+ Log.d("ActiveUnlock", "reportUserRequestedUnlock triggerReason=" + reason
+ + " dismissKeyguard=" + dismissKeyguard);
+ }
+ mTrustManager.reportUserRequestedUnlock(KeyguardUpdateMonitor.getCurrentUser(),
+ dismissKeyguard);
+ }
+ }
+
+ /**
+ * Attempts to trigger active unlock from trust agent.
+ * Only dismisses the keyguard if only face is enrolled (no FP) and bypass is enabled.
+ */
+ public void requestActiveUnlock(String reason) {
+ requestActiveUnlock(reason, isFaceEnrolled() && !isUdfpsEnrolled()
+ && mKeyguardBypassController.getBypassEnabled());
+ }
+
+ /**
+ * Whether the UDFPS bouncer is showing.
+ */
+ public void setUdfpsBouncerShowing(boolean showing) {
+ mUdfpsBouncerShowing = showing;
+ if (mUdfpsBouncerShowing) {
+ updateFaceListeningState(BIOMETRIC_ACTION_START);
+ if (mRequestActiveUnlockOnUnlockIntent) {
+ requestActiveUnlock("unlock-intent, extra=udfpsBouncer", true);
+ }
+ }
+ }
+
private boolean shouldTriggerActiveUnlock() {
// Triggers:
final boolean triggerActiveUnlockForAssistant = shouldTriggerActiveUnlockForAssistant();
- final boolean awakeKeyguard = mKeyguardIsVisible && mDeviceInteractive && !mGoingToSleep
- && mStatusBarState != StatusBarState.SHADE_LOCKED;
+ final boolean awakeKeyguard = mBouncerFullyShown || mUdfpsBouncerShowing
+ || (mKeyguardIsVisible && mDeviceInteractive && !mGoingToSleep
+ && mStatusBarState != StatusBarState.SHADE_LOCKED);
// Gates:
final int user = getCurrentUser();
@@ -2341,20 +2441,19 @@
&& !mSecureCameraLaunched;
// Aggregate relevant fields for debug logging.
- if (DEBUG_ACTIVE_UNLOCK || DEBUG_SPEW) {
- maybeLogListenerModelData(
- new KeyguardActiveUnlockModel(
- System.currentTimeMillis(),
- user,
- shouldTriggerActiveUnlock,
- mAuthInterruptActive,
- isEncryptedOrTimedOut,
- fpLockedout,
- isLockDown,
- mSwitchingUser,
- triggerActiveUnlockForAssistant,
- userCanDismissLockScreen));
- }
+ maybeLogListenerModelData(
+ new KeyguardActiveUnlockModel(
+ System.currentTimeMillis(),
+ user,
+ shouldTriggerActiveUnlock,
+ awakeKeyguard,
+ mAuthInterruptActive,
+ isEncryptedOrTimedOut,
+ fpLockedout,
+ isLockDown,
+ mSwitchingUser,
+ triggerActiveUnlockForAssistant,
+ userCanDismissLockScreen));
return shouldTriggerActiveUnlock;
}
@@ -2507,7 +2606,8 @@
|| mOccludingAppRequestingFace
|| awakeKeyguard
|| shouldListenForFaceAssistant
- || mAuthController.isUdfpsFingerDown())
+ || mAuthController.isUdfpsFingerDown()
+ || mUdfpsBouncerShowing)
&& !mSwitchingUser && !faceDisabledForUser && becauseCannotSkipBouncer
&& !mKeyguardGoingAway && biometricEnabledForUser && !mLockIconPressed
&& strongAuthAllowsScanning && mIsPrimaryUser
@@ -2537,7 +2637,8 @@
mIsPrimaryUser,
strongAuthAllowsScanning,
mSecureCameraLaunched,
- mSwitchingUser));
+ mSwitchingUser,
+ mUdfpsBouncerShowing));
}
return shouldListen;
@@ -2550,8 +2651,7 @@
}
if (DEBUG_ACTIVE_UNLOCK
- && model instanceof KeyguardActiveUnlockModel
- && model.getListening()) {
+ && model instanceof KeyguardActiveUnlockModel) {
mListenModels.add(model);
return;
}
@@ -3133,6 +3233,9 @@
}
if (wasBouncerFullyShown != mBouncerFullyShown) {
+ if (mBouncerFullyShown && mRequestActiveUnlockOnUnlockIntent) {
+ requestActiveUnlock("unlock-intent, reason=bouncerFullyShown", true);
+ }
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
@@ -3619,8 +3722,8 @@
final int strongAuthFlags = mStrongAuthTracker.getStrongAuthForUser(userId);
BiometricAuthenticated fingerprint = mUserFingerprintAuthenticated.get(userId);
pw.println(" Fingerprint state (user=" + userId + ")");
- pw.println(" areAllAuthenticatorsRegistered="
- + mAuthController.areAllAuthenticatorsRegistered());
+ pw.println(" areAllFpAuthenticatorsRegistered="
+ + mAuthController.areAllFingerprintAuthenticatorsRegistered());
pw.println(" allowed="
+ (fingerprint != null
&& isUnlockingWithBiometricAllowed(fingerprint.mIsStrongBiometric)));
@@ -3641,6 +3744,7 @@
pw.println(" shouldListenForUdfps=" + shouldListenForFingerprint(true));
pw.println(" mBouncerIsOrWillBeShowing=" + mBouncerIsOrWillBeShowing);
pw.println(" mStatusBarState=" + StatusBarState.toString(mStatusBarState));
+ pw.println(" mUdfpsBouncerShowing=" + mUdfpsBouncerShowing);
}
}
if (mFaceManager != null && mFaceManager.isHardwareDetected()) {
@@ -3667,6 +3771,13 @@
}
mListenModels.print(pw);
+ pw.println("Enabled active unlock triggers:");
+ pw.println(" mRequestActiveUnlockOnWakeup=" + mRequestActiveUnlockOnWakeup);
+ pw.println(" mInitiateActiveUnlockOnWakeup=" + mInitiateActiveUnlockOnWakeup);
+ pw.println(" mRequestActiveUnlockOnUnlockIntent=" + mRequestActiveUnlockOnUnlockIntent);
+ pw.println(" mRequestActiveUnlockOnBiometricFail=" + mRequestActiveUnlockOnBioFail);
+ pw.println(" mRequestActiveUnlockOnAssistant=" + mRequestActiveUnlockOnAssistant);
+
if (mIsAutomotive) {
pw.println(" Running on Automotive build");
}
diff --git a/packages/SystemUI/src/com/android/systemui/LatencyTester.java b/packages/SystemUI/src/com/android/systemui/LatencyTester.java
index 7afd43d..9cdce64 100644
--- a/packages/SystemUI/src/com/android/systemui/LatencyTester.java
+++ b/packages/SystemUI/src/com/android/systemui/LatencyTester.java
@@ -23,21 +23,31 @@
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricSourceType;
import android.os.Build;
+import android.provider.DeviceConfig;
+import androidx.annotation.NonNull;
+
+import com.android.internal.util.LatencyTracker;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
+import com.android.systemui.util.DeviceConfigProxy;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+
+import java.io.PrintWriter;
import javax.inject.Inject;
/**
- * Class that only runs on debuggable builds that listens to broadcasts that simulate actions in the
+ * Class that only runs on debuggable builds with the LatencyTracker setting enabled
+ * that listens to broadcasts that simulate actions in the
* system that are used for testing the latency.
*/
@SysUISingleton
public class LatencyTester extends CoreStartable {
-
+ private static final boolean DEFAULT_ENABLED = Build.IS_ENG;
private static final String
ACTION_FINGERPRINT_WAKE =
"com.android.systemui.latency.ACTION_FINGERPRINT_WAKE";
@@ -46,42 +56,78 @@
"com.android.systemui.latency.ACTION_FACE_WAKE";
private final BiometricUnlockController mBiometricUnlockController;
private final BroadcastDispatcher mBroadcastDispatcher;
+ private final DeviceConfigProxy mDeviceConfigProxy;
+
+ private boolean mEnabled;
@Inject
- public LatencyTester(Context context, BiometricUnlockController biometricUnlockController,
- BroadcastDispatcher broadcastDispatcher) {
+ public LatencyTester(
+ Context context,
+ BiometricUnlockController biometricUnlockController,
+ BroadcastDispatcher broadcastDispatcher,
+ DeviceConfigProxy deviceConfigProxy,
+ @Main DelayableExecutor mainExecutor
+ ) {
super(context);
-
mBiometricUnlockController = biometricUnlockController;
mBroadcastDispatcher = broadcastDispatcher;
+ mDeviceConfigProxy = deviceConfigProxy;
+
+ updateEnabled();
+ mDeviceConfigProxy.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_LATENCY_TRACKER,
+ mainExecutor, properties -> updateEnabled());
}
@Override
public void start() {
- if (!Build.IS_DEBUGGABLE) {
- return;
- }
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(ACTION_FINGERPRINT_WAKE);
- filter.addAction(ACTION_FACE_WAKE);
- mBroadcastDispatcher.registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (ACTION_FINGERPRINT_WAKE.equals(action)) {
- fakeWakeAndUnlock(BiometricSourceType.FINGERPRINT);
- } else if (ACTION_FACE_WAKE.equals(action)) {
- fakeWakeAndUnlock(BiometricSourceType.FACE);
- }
- }
- }, filter);
+ registerForBroadcasts(mEnabled);
}
private void fakeWakeAndUnlock(BiometricSourceType type) {
+ if (!mEnabled) {
+ return;
+ }
mBiometricUnlockController.onBiometricAcquired(type,
BiometricConstants.BIOMETRIC_ACQUIRED_GOOD);
mBiometricUnlockController.onBiometricAuthenticated(
KeyguardUpdateMonitor.getCurrentUser(), type, true /* isStrongBiometric */);
}
+
+ private void registerForBroadcasts(boolean register) {
+ if (register) {
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(ACTION_FINGERPRINT_WAKE);
+ filter.addAction(ACTION_FACE_WAKE);
+ mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter);
+ } else {
+ mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver);
+ }
+ }
+
+ private void updateEnabled() {
+ boolean wasEnabled = mEnabled;
+ mEnabled = Build.IS_DEBUGGABLE
+ && mDeviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_LATENCY_TRACKER,
+ LatencyTracker.SETTINGS_ENABLED_KEY, DEFAULT_ENABLED);
+ if (mEnabled != wasEnabled) {
+ registerForBroadcasts(mEnabled);
+ }
+ }
+
+ @Override
+ public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
+ pw.println("mEnabled=" + mEnabled);
+ }
+
+ private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (ACTION_FINGERPRINT_WAKE.equals(action)) {
+ fakeWakeAndUnlock(BiometricSourceType.FINGERPRINT);
+ } else if (ACTION_FACE_WAKE.equals(action)) {
+ fakeWakeAndUnlock(BiometricSourceType.FACE);
+ }
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/ModeSwitchesController.java b/packages/SystemUI/src/com/android/systemui/accessibility/ModeSwitchesController.java
index 5e48ee3..0cc1b2d 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/ModeSwitchesController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/ModeSwitchesController.java
@@ -28,6 +28,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.dagger.SysUISingleton;
+import javax.inject.Inject;
+
/**
* A class to control {@link MagnificationModeSwitch}. It shows the button UI with following
* conditions:
@@ -44,6 +46,7 @@
private final DisplayIdIndexSupplier<MagnificationModeSwitch> mSwitchSupplier;
private SwitchListener mSwitchListenerDelegate;
+ @Inject
public ModeSwitchesController(Context context) {
mSwitchSupplier = new SwitchSupplier(context,
context.getSystemService(DisplayManager.class), this::onSwitch);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AlternateUdfpsTouchProvider.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AlternateUdfpsTouchProvider.kt
new file mode 100644
index 0000000..f4f39a1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AlternateUdfpsTouchProvider.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 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.biometrics
+
+/**
+ * Interface for controlling the on finger down & on finger up events.
+ */
+interface AlternateUdfpsTouchProvider {
+
+ /**
+ * This operation is used to notify the Fingerprint HAL that
+ * a fingerprint has been detected on the device's screen.
+ *
+ * See fingerprint/ISession#onPointerDown for more details.
+ */
+ fun onPointerDown(pointerId: Long, x: Int, y: Int, minor: Float, major: Float)
+
+ /**
+ * onPointerUp:
+ *
+ * This operation can be invoked when the HAL is performing any one of: ISession#authenticate,
+ * ISession#enroll, ISession#detectInteraction. This operation is used to indicate
+ * that a fingerprint that was previously down, is now up.
+ *
+ * See fingerprint/ISession#onPointerUp for more details.
+ */
+ fun onPointerUp(pointerId: Long)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index b05bc24..15d0648 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -37,6 +37,7 @@
import android.hardware.biometrics.BiometricManager.Authenticators;
import android.hardware.biometrics.BiometricManager.BiometricMultiSensorMode;
import android.hardware.biometrics.BiometricPrompt;
+import android.hardware.biometrics.BiometricStateListener;
import android.hardware.biometrics.IBiometricContextListener;
import android.hardware.biometrics.IBiometricSysuiReceiver;
import android.hardware.biometrics.PromptInfo;
@@ -45,7 +46,6 @@
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
-import android.hardware.fingerprint.FingerprintStateListener;
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
import android.hardware.fingerprint.IUdfpsHbmListener;
import android.os.Bundle;
@@ -138,7 +138,7 @@
@NonNull private final SparseBooleanArray mUdfpsEnrolledForUser;
@NonNull private final SensorPrivacyManager mSensorPrivacyManager;
private final WakefulnessLifecycle mWakefulnessLifecycle;
- private boolean mAllAuthenticatorsRegistered;
+ private boolean mAllFingerprintAuthenticatorsRegistered;
@NonNull private final UserManager mUserManager;
@NonNull private final LockPatternUtils mLockPatternUtils;
private final @Background DelayableExecutor mBackgroundExecutor;
@@ -157,12 +157,12 @@
@Override
public void onAllAuthenticatorsRegistered(
List<FingerprintSensorPropertiesInternal> sensors) {
- mHandler.post(() -> handleAllAuthenticatorsRegistered(sensors));
+ mHandler.post(() -> handleAllFingerprintAuthenticatorsRegistered(sensors));
}
};
- private final FingerprintStateListener mFingerprintStateListener =
- new FingerprintStateListener() {
+ private final BiometricStateListener mBiometricStateListener =
+ new BiometricStateListener() {
@Override
public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) {
mHandler.post(
@@ -234,20 +234,20 @@
}
/**
- * Whether all authentictors have been registered.
+ * Whether all fingerprint authentictors have been registered.
*/
- public boolean areAllAuthenticatorsRegistered() {
- return mAllAuthenticatorsRegistered;
+ public boolean areAllFingerprintAuthenticatorsRegistered() {
+ return mAllFingerprintAuthenticatorsRegistered;
}
- private void handleAllAuthenticatorsRegistered(
+ private void handleAllFingerprintAuthenticatorsRegistered(
List<FingerprintSensorPropertiesInternal> sensors) {
mExecution.assertIsMainThread();
if (DEBUG) {
Log.d(TAG, "handleAllAuthenticatorsRegistered | sensors: " + Arrays.toString(
sensors.toArray()));
}
- mAllAuthenticatorsRegistered = true;
+ mAllFingerprintAuthenticatorsRegistered = true;
mFpProps = sensors;
List<FingerprintSensorPropertiesInternal> udfpsProps = new ArrayList<>();
List<FingerprintSensorPropertiesInternal> sidefpsProps = new ArrayList<>();
@@ -281,7 +281,7 @@
for (Callback cb : mCallbacks) {
cb.onAllAuthenticatorsRegistered();
}
- mFingerprintManager.registerFingerprintStateListener(mFingerprintStateListener);
+ mFingerprintManager.registerBiometricStateListener(mBiometricStateListener);
}
private void handleEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 2ac2408..2847246 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -133,6 +133,7 @@
// sensors, this, in addition to a lot of the code here, will be updated.
@VisibleForTesting final FingerprintSensorPropertiesInternal mSensorProps;
@NonNull private final ActivityLaunchAnimator mActivityLaunchAnimator;
+ @Nullable private final AlternateUdfpsTouchProvider mAlternateTouchProvider;
// Tracks the velocity of a touch to help filter out the touches that move too fast.
@Nullable private VelocityTracker mVelocityTracker;
@@ -384,6 +385,7 @@
mActivePointerId = event.getPointerId(0);
mVelocityTracker.addMovement(event);
handled = true;
+ mAcquiredReceived = false;
}
if ((withinSensorArea || fromUdfpsView) && shouldTryToDismissKeyguard()) {
Log.v(TAG, "onTouch | dismiss keyguard ACTION_DOWN");
@@ -537,7 +539,8 @@
@NonNull UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
@NonNull SystemUIDialogManager dialogManager,
@NonNull LatencyTracker latencyTracker,
- @NonNull ActivityLaunchAnimator activityLaunchAnimator) {
+ @NonNull ActivityLaunchAnimator activityLaunchAnimator,
+ @NonNull Optional<AlternateUdfpsTouchProvider> aternateTouchProvider) {
mContext = context;
mExecution = execution;
mVibrator = vibrator;
@@ -566,6 +569,7 @@
mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
mLatencyTracker = latencyTracker;
mActivityLaunchAnimator = activityLaunchAnimator;
+ mAlternateTouchProvider = aternateTouchProvider.orElse(null);
mSensorProps = findFirstUdfps();
// At least one UDFPS sensor exists
@@ -782,6 +786,7 @@
private void onFingerDown(long requestId, int x, int y, float minor, float major) {
mExecution.assertIsMainThread();
+
if (mOverlay == null) {
Log.w(TAG, "Null request in onFingerDown");
return;
@@ -799,9 +804,18 @@
if (!mKeyguardUpdateMonitor.isFaceDetectionRunning()) {
mKeyguardUpdateMonitor.requestFaceAuth(/* userInitiatedRequest */ false);
}
+
+ if (mKeyguardUpdateMonitor.mRequestActiveUnlockOnUnlockIntent) {
+ mKeyguardUpdateMonitor.requestActiveUnlock("unlock-intent extra=udfpsFingerDown",
+ true);
+ }
}
mOnFingerDown = true;
- mFingerprintManager.onPointerDown(requestId, mSensorProps.sensorId, x, y, minor, major);
+ if (mAlternateTouchProvider != null) {
+ mAlternateTouchProvider.onPointerDown(requestId, x, y, minor, major);
+ } else {
+ mFingerprintManager.onPointerDown(requestId, mSensorProps.sensorId, x, y, minor, major);
+ }
Trace.endAsyncSection("UdfpsController.e2e.onPointerDown", 0);
final UdfpsView view = mOverlay.getOverlayView();
@@ -822,7 +836,11 @@
mActivePointerId = -1;
mAcquiredReceived = false;
if (mOnFingerDown) {
- mFingerprintManager.onPointerUp(requestId, mSensorProps.sensorId);
+ if (mAlternateTouchProvider != null) {
+ mAlternateTouchProvider.onPointerUp(requestId);
+ } else {
+ mFingerprintManager.onPointerUp(requestId, mSensorProps.sensorId);
+ }
for (Callback cb : mCallbacks) {
cb.onFingerUp();
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
index f5f07c8..4ec479a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
@@ -21,7 +21,6 @@
import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.content.res.Configuration;
-import android.util.Log;
import android.util.MathUtils;
import android.view.MotionEvent;
@@ -83,7 +82,7 @@
* {@link KeyguardBouncer#EXPANSION_HIDDEN} (1f)
*/
private float mInputBouncerHiddenAmount;
- private boolean mIsBouncerVisible;
+ private boolean mIsGenericBouncerShowing; // whether UDFPS bouncer or input bouncer is visible
protected UdfpsKeyguardViewController(
@NonNull UdfpsKeyguardView view,
@@ -151,8 +150,7 @@
mKeyguardStateController.addCallback(mKeyguardStateControllerCallback);
mStatusBarState = getStatusBarStateController().getState();
mQsExpanded = mKeyguardViewManager.isQsExpanded();
- mInputBouncerHiddenAmount = KeyguardBouncer.EXPANSION_HIDDEN;
- mIsBouncerVisible = mKeyguardViewManager.bouncerIsOrWillBeShowing();
+ updateGenericBouncerVisibility();
mConfigurationController.addCallback(mConfigurationListener);
getPanelExpansionStateManager().addExpansionListener(mPanelExpansionListener);
updateAlpha();
@@ -187,7 +185,7 @@
pw.println("mFaceDetectRunning=" + mFaceDetectRunning);
pw.println("mStatusBarState=" + StatusBarState.toString(mStatusBarState));
pw.println("mQsExpanded=" + mQsExpanded);
- pw.println("mIsBouncerVisible=" + mIsBouncerVisible);
+ pw.println("mIsGenericBouncerShowing=" + mIsGenericBouncerShowing);
pw.println("mInputBouncerHiddenAmount=" + mInputBouncerHiddenAmount);
pw.println("mPanelExpansionFraction=" + mPanelExpansionFraction);
pw.println("unpausedAlpha=" + mView.getUnpausedAlpha());
@@ -225,6 +223,8 @@
} else {
mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false);
}
+
+ updateGenericBouncerVisibility();
updateAlpha();
updatePauseAuth();
return true;
@@ -241,7 +241,7 @@
}
if (mUdfpsRequested && !getNotificationShadeVisible()
- && (!mIsBouncerVisible
+ && (!mIsGenericBouncerShowing
|| mInputBouncerHiddenAmount != KeyguardBouncer.EXPANSION_VISIBLE)
&& mKeyguardStateController.isShowing()) {
return false;
@@ -267,13 +267,8 @@
return true;
}
- if (mInputBouncerHiddenAmount < .5f || mIsBouncerVisible) {
- if (!getStatusBarStateController().isDozing()) {
- return true;
- } else {
- Log.e(TAG, "Bouncer state claims visible on doze hiddenAmount="
- + mInputBouncerHiddenAmount + " bouncerVisible=" + mIsBouncerVisible);
- }
+ if (mInputBouncerHiddenAmount < .5f) {
+ return true;
}
return false;
@@ -351,6 +346,21 @@
mView.setUnpausedAlpha(alpha);
}
+ /**
+ * Updates mIsGenericBouncerShowing (whether any bouncer is showing) and updates the
+ * mInputBouncerHiddenAmount to reflect whether the input bouncer is fully showing or not.
+ */
+ private void updateGenericBouncerVisibility() {
+ mIsGenericBouncerShowing = mKeyguardViewManager.isBouncerShowing(); // includes altBouncer
+ final boolean altBouncerShowing = mKeyguardViewManager.isShowingAlternateAuth();
+ if (altBouncerShowing || !mKeyguardViewManager.bouncerIsOrWillBeShowing()) {
+ mInputBouncerHiddenAmount = 1f;
+ } else if (mIsGenericBouncerShowing) {
+ // input bouncer is fully showing
+ mInputBouncerHiddenAmount = 0f;
+ }
+ }
+
private final StatusBarStateController.StateListener mStateListener =
new StatusBarStateController.StateListener() {
@Override
@@ -434,14 +444,13 @@
updatePauseAuth();
}
+ /**
+ * Only called on primary auth bouncer changes, not on whether the UDFPS bouncer
+ * visibility changes.
+ */
@Override
public void onBouncerVisibilityChanged() {
- mIsBouncerVisible = mKeyguardViewManager.isBouncerShowing();
- if (!mIsBouncerVisible) {
- mInputBouncerHiddenAmount = 1f;
- } else if (mKeyguardViewManager.isBouncerShowing()) {
- mInputBouncerHiddenAmount = 0f;
- }
+ updateGenericBouncerVisibility();
updateAlpha();
updatePauseAuth();
}
@@ -475,7 +484,7 @@
public void onPanelExpansionChanged(
float fraction, boolean expanded, boolean tracking) {
mPanelExpansionFraction =
- mKeyguardViewManager.bouncerIsInTransit() ? BouncerPanelExpansionCalculator
+ mKeyguardViewManager.isBouncerInTransit() ? BouncerPanelExpansionCalculator
.aboutToShowBouncerProgress(fraction) : fraction;
updateAlpha();
}
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
index b7aebc1..d757b62 100644
--- a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
@@ -31,10 +31,13 @@
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.Dumpable
import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dump.DumpManager
import com.android.systemui.settings.UserTracker
import java.io.PrintWriter
import java.util.concurrent.Executor
+import javax.inject.Inject
data class ReceiverData(
val receiver: BroadcastReceiver,
@@ -63,14 +66,15 @@
* Broadcast handling may be asynchronous *without* calling goAsync(), as it's running within sysui
* and doesn't need to worry about being killed.
*/
-open class BroadcastDispatcher @JvmOverloads constructor (
+@SysUISingleton
+open class BroadcastDispatcher @Inject constructor(
private val context: Context,
- private val bgLooper: Looper,
- private val bgExecutor: Executor,
+ @Background private val bgLooper: Looper,
+ @Background private val bgExecutor: Executor,
private val dumpManager: DumpManager,
private val logger: BroadcastDispatcherLogger,
private val userTracker: UserTracker,
- private val removalPendingStore: PendingRemovalStore = PendingRemovalStore(logger)
+ private val removalPendingStore: PendingRemovalStore
) : Dumpable {
// Only modify in BG thread
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcherModule.java b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcherModule.java
new file mode 100644
index 0000000..cc08188
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcherModule.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 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.broadcast;
+
+import com.android.systemui.CoreStartable;
+
+import dagger.Binds;
+import dagger.Module;
+import dagger.multibindings.ClassKey;
+import dagger.multibindings.IntoMap;
+
+/** */
+@Module
+public abstract class BroadcastDispatcherModule {
+ /** Ensures BroadcastDispatcher is initialized. */
+ @Binds
+ @IntoMap
+ @ClassKey(BroadcastDispatcherStartable.class)
+ abstract CoreStartable bindsBroadastDispatcherStartable(BroadcastDispatcherStartable s);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcherStartable.kt b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcherStartable.kt
new file mode 100644
index 0000000..d7b263a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcherStartable.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 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.broadcast
+
+import android.content.Context
+import com.android.systemui.CoreStartable
+import javax.inject.Inject
+
+class BroadcastDispatcherStartable @Inject constructor(
+ context: Context,
+ val broadcastDispatcher: BroadcastDispatcher
+) : CoreStartable(context) {
+
+ override fun start() {
+ broadcastDispatcher.initialize()
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/PendingRemovalStore.kt b/packages/SystemUI/src/com/android/systemui/broadcast/PendingRemovalStore.kt
index ebf4983..a5d730f 100644
--- a/packages/SystemUI/src/com/android/systemui/broadcast/PendingRemovalStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/PendingRemovalStore.kt
@@ -8,6 +8,7 @@
import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger
import com.android.systemui.util.indentIfPossible
import java.io.PrintWriter
+import javax.inject.Inject
/**
* Store information about requests for unregistering receivers from [BroadcastDispatcher], before
@@ -15,7 +16,7 @@
*
* This helps make unregistering a receiver a *sync* operation.
*/
-class PendingRemovalStore(
+class PendingRemovalStore @Inject constructor(
private val logger: BroadcastDispatcherLogger
) : Dumpable {
@GuardedBy("pendingRemoval")
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/AndroidInternalsModule.java b/packages/SystemUI/src/com/android/systemui/dagger/AndroidInternalsModule.java
new file mode 100644
index 0000000..48c54bc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dagger/AndroidInternalsModule.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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 android.content.Context;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.util.NotificationMessagingUtil;
+import com.android.internal.widget.LockPatternUtils;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Provides items imported from com.android.internal.
+ */
+@Module
+public class AndroidInternalsModule {
+ /** */
+ @Provides
+ @SysUISingleton
+ public LockPatternUtils provideLockPatternUtils(Context context) {
+ return new LockPatternUtils(context);
+ }
+
+ /** */
+ @Provides
+ @SysUISingleton
+ public MetricsLogger provideMetricsLogger() {
+ return new MetricsLogger();
+ }
+
+ /** */
+ @Provides
+ public NotificationMessagingUtil provideNotificationMessagingUtil(Context context) {
+ return new NotificationMessagingUtil(context);
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
index 1653e0a..fb01691 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
@@ -29,8 +29,10 @@
import com.android.systemui.settings.brightness.BrightnessDialog;
import com.android.systemui.statusbar.tv.notifications.TvNotificationPanelActivity;
import com.android.systemui.tuner.TunerActivity;
+import com.android.systemui.usb.UsbConfirmActivity;
import com.android.systemui.usb.UsbDebuggingActivity;
import com.android.systemui.usb.UsbDebuggingSecondaryUserActivity;
+import com.android.systemui.usb.UsbPermissionActivity;
import com.android.systemui.user.CreateUserActivity;
import dagger.Binds;
@@ -80,6 +82,18 @@
public abstract Activity bindUsbDebuggingSecondaryUserActivity(
UsbDebuggingSecondaryUserActivity activity);
+ /** Inject into UsbPermissionActivity. */
+ @Binds
+ @IntoMap
+ @ClassKey(UsbPermissionActivity.class)
+ public abstract Activity bindUsbPermissionActivity(UsbPermissionActivity activity);
+
+ /** Inject into UsbConfirmActivity. */
+ @Binds
+ @IntoMap
+ @ClassKey(UsbConfirmActivity.class)
+ public abstract Activity bindUsbConfirmActivity(UsbConfirmActivity activity);
+
/** Inject into CreateUserActivity. */
@Binds
@IntoMap
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index fa23842..31ad36f 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -16,279 +16,24 @@
package com.android.systemui.dagger;
-import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME;
-
-import android.annotation.Nullable;
-import android.annotation.SuppressLint;
-import android.app.INotificationManager;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.om.OverlayManager;
-import android.hardware.display.AmbientDisplayConfiguration;
-import android.hardware.display.ColorDisplayManager;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.ServiceManager;
-import android.os.UserHandle;
-import android.view.Choreographer;
-import android.view.IWindowManager;
-import android.view.LayoutInflater;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.util.NotificationMessagingUtil;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.ViewMediatorCallback;
-import com.android.settingslib.bluetooth.LocalBluetoothManager;
-import com.android.systemui.Prefs;
-import com.android.systemui.R;
-import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
-import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
-import com.android.systemui.accessibility.ModeSwitchesController;
-import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController;
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger;
-import com.android.systemui.dagger.qualifiers.Background;
-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.qs.ReduceBrightColorsController;
-import com.android.systemui.settings.UserTracker;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.DevicePolicyManagerWrapper;
-import com.android.systemui.shared.system.TaskStackChangeListeners;
-import com.android.systemui.shared.system.WindowManagerWrapper;
-import com.android.systemui.statusbar.connectivity.NetworkController;
-import com.android.systemui.statusbar.phone.AutoHideController;
-import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.DataSaverController;
-import com.android.systemui.theme.ThemeOverlayApplier;
-import com.android.systemui.util.leak.LeakDetector;
-import com.android.systemui.util.settings.SecureSettings;
-
-import java.util.concurrent.Executor;
-
-import javax.inject.Named;
+import com.android.systemui.broadcast.BroadcastDispatcherModule;
+import com.android.systemui.theme.ThemeModule;
+import com.android.systemui.util.leak.LeakModule;
import dagger.Module;
-import dagger.Provides;
/**
- * Provides dependencies for the root component of sysui injection.
- *
- * Only SystemUI owned classes and instances should go in here. Other, framework-owned classes
- * should go in {@link FrameworkServicesModule}.
- *
- * See SystemUI/docs/dagger.md
+ * @deprecated This module is going away. Don't put anything in here.
*/
-@Module(includes = {NightDisplayListenerModule.class})
+@Deprecated
+@Module(includes = {
+ AndroidInternalsModule.class,
+ BroadcastDispatcherModule.class,
+ LeakModule.class,
+ NightDisplayListenerModule.class,
+ SharedLibraryModule.class,
+ SettingsLibraryModule.class,
+ ThemeModule.class
+})
public class DependencyProvider {
-
- /** */
- @Provides
- @SysUISingleton
- @Named(TIME_TICK_HANDLER_NAME)
- public Handler provideTimeTickHandler() {
- HandlerThread thread = new HandlerThread("TimeTick");
- thread.start();
- return new Handler(thread.getLooper());
- }
-
- /** */
- @Provides
- @Main
- public SharedPreferences provideSharePreferences(Context context) {
- return Prefs.get(context);
- }
-
- /** */
- @Provides
- public AmbientDisplayConfiguration provideAmbientDisplayConfiguration(Context context) {
- return new AmbientDisplayConfiguration(context);
- }
-
- /** */
- @Provides
- public Handler provideHandler() {
- return new Handler();
- }
-
- /** */
- @Provides
- @SysUISingleton
- public DataSaverController provideDataSaverController(NetworkController networkController) {
- return networkController.getDataSaverController();
- }
-
- @Provides
- @SysUISingleton
- public INotificationManager provideINotificationManager() {
- return INotificationManager.Stub.asInterface(
- ServiceManager.getService(Context.NOTIFICATION_SERVICE));
- }
-
- /** */
- @Provides
- @SysUISingleton
- public LayoutInflater providerLayoutInflater(Context context) {
- return LayoutInflater.from(context);
- }
-
- /** */
- @Provides
- @SysUISingleton
- public LeakDetector provideLeakDetector(DumpManager dumpManager) {
- return LeakDetector.create(dumpManager);
- }
-
- @SuppressLint("MissingPermission")
- @SysUISingleton
- @Provides
- @Nullable
- static LocalBluetoothManager provideLocalBluetoothController(Context context,
- @Background Handler bgHandler) {
- return LocalBluetoothManager.create(context, bgHandler, UserHandle.ALL);
- }
-
- /** */
- @Provides
- @SysUISingleton
- public MetricsLogger provideMetricsLogger() {
- return new MetricsLogger();
- }
-
- /** */
- @SysUISingleton
- @Provides
- static ThemeOverlayApplier provideThemeOverlayManager(Context context,
- @Background Executor bgExecutor,
- @Main Executor mainExecutor,
- OverlayManager overlayManager,
- DumpManager dumpManager) {
- return new ThemeOverlayApplier(overlayManager, bgExecutor, mainExecutor,
- context.getString(R.string.launcher_overlayable_package),
- context.getString(R.string.themepicker_overlayable_package), dumpManager);
- }
-
- /** */
- @Provides
- @SysUISingleton
- public AccessibilityFloatingMenuController provideAccessibilityFloatingMenuController(
- Context context, AccessibilityButtonTargetsObserver accessibilityButtonTargetsObserver,
- AccessibilityButtonModeObserver accessibilityButtonModeObserver,
- KeyguardUpdateMonitor keyguardUpdateMonitor) {
- return new AccessibilityFloatingMenuController(context, accessibilityButtonTargetsObserver,
- accessibilityButtonModeObserver, keyguardUpdateMonitor);
- }
-
- /** */
- @Provides
- @SysUISingleton
- public ConfigurationController provideConfigurationController(Context context) {
- return new ConfigurationControllerImpl(context);
- }
-
- /** */
- @SysUISingleton
- @Provides
- public AutoHideController provideAutoHideController(Context context,
- @Main Handler mainHandler, IWindowManager iWindowManager) {
- return new AutoHideController(context, mainHandler, iWindowManager);
- }
-
- /** */
- @SysUISingleton
- @Provides
- public ReduceBrightColorsController provideReduceBrightColorsListener(
- @Background Handler bgHandler, UserTracker userTracker,
- ColorDisplayManager colorDisplayManager, SecureSettings secureSettings) {
- return new ReduceBrightColorsController(userTracker, bgHandler,
- colorDisplayManager, secureSettings);
- }
-
- @Provides
- @SysUISingleton
- public ActivityManagerWrapper provideActivityManagerWrapper() {
- return ActivityManagerWrapper.getInstance();
- }
-
- /** */
- @Provides
- @SysUISingleton
- public TaskStackChangeListeners provideTaskStackChangeListeners() {
- return TaskStackChangeListeners.getInstance();
- }
-
- /** Provides and initializes the {#link BroadcastDispatcher} for SystemUI */
- @Provides
- @SysUISingleton
- public BroadcastDispatcher providesBroadcastDispatcher(
- Context context,
- @Background Looper backgroundLooper,
- @Background Executor backgroundExecutor,
- DumpManager dumpManager,
- BroadcastDispatcherLogger logger,
- UserTracker userTracker
- ) {
- BroadcastDispatcher bD = new BroadcastDispatcher(context, backgroundLooper,
- backgroundExecutor, dumpManager, logger, userTracker);
- bD.initialize();
- return bD;
- }
-
- /** */
- @Provides
- @SysUISingleton
- public DevicePolicyManagerWrapper provideDevicePolicyManagerWrapper() {
- return DevicePolicyManagerWrapper.getInstance();
- }
-
- /** */
- @Provides
- @SysUISingleton
- public LockPatternUtils provideLockPatternUtils(Context context) {
- return new LockPatternUtils(context);
- }
-
- /** */
- @Provides
- @SysUISingleton
- public AlwaysOnDisplayPolicy provideAlwaysOnDisplayPolicy(Context context) {
- return new AlwaysOnDisplayPolicy(context);
- }
-
- /***/
- @Provides
- public NotificationMessagingUtil provideNotificationMessagingUtil(Context context) {
- return new NotificationMessagingUtil(context);
- }
-
- /** */
- @Provides
- public ViewMediatorCallback providesViewMediatorCallback(KeyguardViewMediator viewMediator) {
- return viewMediator.getViewMediatorCallback();
- }
-
- /** */
- @Provides
- public WindowManagerWrapper providesWindowManagerWrapper() {
- return WindowManagerWrapper.getInstance();
- }
-
- /** */
- @Provides
- @SysUISingleton
- public Choreographer providesChoreographer() {
- return Choreographer.getInstance();
- }
-
- /** */
- @Provides
- @SysUISingleton
- public ModeSwitchesController providesModeSwitchesController(Context context) {
- return new ModeSwitchesController(context);
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index 535b548..e512b7c 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -22,6 +22,7 @@
import android.app.AlarmManager;
import android.app.IActivityManager;
import android.app.IActivityTaskManager;
+import android.app.INotificationManager;
import android.app.IWallpaperManager;
import android.app.KeyguardManager;
import android.app.NotificationManager;
@@ -35,6 +36,7 @@
import android.content.ClipboardManager;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.SharedPreferences;
import android.content.om.OverlayManager;
import android.content.pm.IPackageManager;
import android.content.pm.LauncherApps;
@@ -44,6 +46,7 @@
import android.hardware.SensorManager;
import android.hardware.SensorPrivacyManager;
import android.hardware.devicestate.DeviceStateManager;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.display.ColorDisplayManager;
import android.hardware.display.DisplayManager;
import android.hardware.face.FaceManager;
@@ -68,8 +71,10 @@
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.view.Choreographer;
import android.view.CrossWindowBlurListeners;
import android.view.IWindowManager;
+import android.view.LayoutInflater;
import android.view.ViewConfiguration;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
@@ -82,6 +87,7 @@
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.LatencyTracker;
+import com.android.systemui.Prefs;
import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.shared.system.PackageManagerWrapper;
@@ -116,6 +122,12 @@
return context.getSystemService(AlarmManager.class);
}
+ /** */
+ @Provides
+ public AmbientDisplayConfiguration provideAmbientDisplayConfiguration(Context context) {
+ return new AmbientDisplayConfiguration(context);
+ }
+
@Provides
@Singleton
static AudioManager provideAudioManager(Context context) {
@@ -128,6 +140,13 @@
return context.getSystemService(CaptioningManager.class);
}
+ /** */
+ @Provides
+ @Singleton
+ public Choreographer providesChoreographer() {
+ return Choreographer.getInstance();
+ }
+
@Provides
@Singleton
static ColorDisplayManager provideColorDisplayManager(Context context) {
@@ -293,6 +312,13 @@
return context.getSystemService(LauncherApps.class);
}
+ /** */
+ @Provides
+ @Singleton
+ public LayoutInflater providerLayoutInflater(Context context) {
+ return LayoutInflater.from(context);
+ }
+
@Provides
static MediaRouter2Manager provideMediaRouter2Manager(Context context) {
return MediaRouter2Manager.getInstance(context);
@@ -315,6 +341,14 @@
return context.getSystemService(NotificationManager.class);
}
+ /** */
+ @Provides
+ @Singleton
+ public INotificationManager provideINotificationManager() {
+ return INotificationManager.Stub.asInterface(
+ ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+ }
+
@Provides
@Singleton
static PackageManager providePackageManager(Context context) {
@@ -336,6 +370,13 @@
/** */
@Provides
+ @Main
+ public SharedPreferences provideSharePreferences(Context context) {
+ return Prefs.get(context);
+ }
+
+ /** */
+ @Provides
@Singleton
static UiModeManager provideUiModeManager(Context context) {
return context.getSystemService(UiModeManager.class);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SettingsLibraryModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SettingsLibraryModule.java
new file mode 100644
index 0000000..14626e1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SettingsLibraryModule.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 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 android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.os.Handler;
+import android.os.UserHandle;
+
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.systemui.dagger.qualifiers.Background;
+
+import dagger.Module;
+import dagger.Provides;
+
+/** */
+@Module
+public class SettingsLibraryModule {
+
+ /** */
+ @SuppressLint("MissingPermission")
+ @SysUISingleton
+ @Provides
+ @Nullable
+ static LocalBluetoothManager provideLocalBluetoothController(Context context,
+ @Background Handler bgHandler) {
+ return LocalBluetoothManager.create(context, bgHandler, UserHandle.ALL);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SharedLibraryModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SharedLibraryModule.java
new file mode 100644
index 0000000..be156157
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SharedLibraryModule.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2022 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 com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.DevicePolicyManagerWrapper;
+import com.android.systemui.shared.system.TaskStackChangeListeners;
+import com.android.systemui.shared.system.WindowManagerWrapper;
+
+import dagger.Module;
+import dagger.Provides;
+
+/** */
+@Module
+public class SharedLibraryModule {
+
+ /** */
+ @Provides
+ @SysUISingleton
+ public ActivityManagerWrapper provideActivityManagerWrapper() {
+ return ActivityManagerWrapper.getInstance();
+ }
+
+ /** */
+ @Provides
+ @SysUISingleton
+ public DevicePolicyManagerWrapper provideDevicePolicyManagerWrapper() {
+ return DevicePolicyManagerWrapper.getInstance();
+ }
+
+ /** */
+ @Provides
+ @SysUISingleton
+ public TaskStackChangeListeners provideTaskStackChangeListeners() {
+ return TaskStackChangeListeners.getInstance();
+ }
+
+ /** */
+ @Provides
+ public WindowManagerWrapper providesWindowManagerWrapper() {
+ return WindowManagerWrapper.getInstance();
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 7b65f45..bbeb66c 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -29,6 +29,7 @@
import com.android.systemui.SystemUIFactory;
import com.android.systemui.appops.dagger.AppOpsModule;
import com.android.systemui.assist.AssistModule;
+import com.android.systemui.biometrics.AlternateUdfpsTouchProvider;
import com.android.systemui.biometrics.UdfpsHbmProvider;
import com.android.systemui.biometrics.dagger.BiometricsModule;
import com.android.systemui.classifier.FalsingModule;
@@ -182,6 +183,9 @@
@BindsOptionalOf
abstract UdfpsHbmProvider optionalUdfpsHbmProvider();
+ @BindsOptionalOf
+ abstract AlternateUdfpsTouchProvider optionalUdfpsTouchProvider();
+
@SysUISingleton
@Binds
abstract SystemClock bindSystemClock(SystemClockImpl systemClock);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java b/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java
index 735b3cd..55df779 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java
@@ -29,11 +29,15 @@
import android.util.Log;
import com.android.systemui.R;
+import com.android.systemui.dagger.SysUISingleton;
+
+import javax.inject.Inject;
/**
* Class to store the policy for AOD, which comes from
* {@link android.provider.Settings.Global}
*/
+@SysUISingleton
public class AlwaysOnDisplayPolicy {
public static final String TAG = "AlwaysOnDisplayPolicy";
@@ -130,6 +134,7 @@
private final Context mContext;
private SettingsObserver mSettingsObserver;
+ @Inject
public AlwaysOnDisplayPolicy(Context context) {
context = context.getApplicationContext();
mContext = context;
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
index d4909c78..e878b22 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
@@ -16,8 +16,13 @@
package com.android.systemui.dreams;
+import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
+import static android.app.StatusBarManager.WINDOW_STATE_HIDING;
+import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
+
import android.annotation.Nullable;
import android.app.AlarmManager;
+import android.app.StatusBarManager;
import android.content.res.Resources;
import android.hardware.SensorPrivacyManager;
import android.net.ConnectivityManager;
@@ -29,6 +34,7 @@
import android.provider.Settings;
import android.text.format.DateFormat;
import android.util.PluralsMessageFormatter;
+import android.view.View;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
@@ -36,6 +42,7 @@
import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
import com.android.systemui.statusbar.policy.NextAlarmController;
import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.statusbar.window.StatusBarWindowStateController;
import com.android.systemui.touch.TouchInsetManager;
import com.android.systemui.util.ViewController;
import com.android.systemui.util.time.DateFormatUtil;
@@ -119,7 +126,8 @@
DateFormatUtil dateFormatUtil,
IndividualSensorPrivacyController sensorPrivacyController,
DreamOverlayNotificationCountProvider dreamOverlayNotificationCountProvider,
- ZenModeController zenModeController) {
+ ZenModeController zenModeController,
+ StatusBarWindowStateController statusBarWindowStateController) {
super(view);
mResources = resources;
mMainExecutor = mainExecutor;
@@ -131,6 +139,10 @@
mSensorPrivacyController = sensorPrivacyController;
mDreamOverlayNotificationCountProvider = dreamOverlayNotificationCountProvider;
mZenModeController = zenModeController;
+
+ // Register to receive show/hide updates for the system status bar. Our custom status bar
+ // needs to hide when the system status bar is showing to ovoid overlapping status bars.
+ statusBarWindowStateController.addListener(this::onSystemStatusBarStateChanged);
}
@Override
@@ -229,4 +241,22 @@
}
});
}
+
+ private void onSystemStatusBarStateChanged(@StatusBarManager.WindowVisibleState int state) {
+ mMainExecutor.execute(() -> {
+ if (!mIsAttached) {
+ return;
+ }
+
+ switch (state) {
+ case WINDOW_STATE_SHOWING:
+ mView.setVisibility(View.INVISIBLE);
+ break;
+ case WINDOW_STATE_HIDING:
+ case WINDOW_STATE_HIDDEN:
+ mView.setVisibility(View.VISIBLE);
+ break;
+ }
+ });
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
index c147fde..54b9430 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java
@@ -42,6 +42,7 @@
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.wm.shell.animation.FlingAnimationUtils;
+import java.util.Optional;
import javax.inject.Inject;
import javax.inject.Named;
@@ -77,7 +78,7 @@
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private float mCurrentExpansion;
- private final CentralSurfaces mCentralSurfaces;
+ private final Optional<CentralSurfaces> mCentralSurfaces;
private VelocityTracker mVelocityTracker;
@@ -107,7 +108,9 @@
// If the user scrolling favors a vertical direction, begin capturing
// scrolls.
mCapture = Math.abs(distanceY) > Math.abs(distanceX);
- mBouncerInitiallyShowing = mCentralSurfaces.isBouncerShowing();
+ mBouncerInitiallyShowing = mCentralSurfaces
+ .map(CentralSurfaces::isBouncerShowing)
+ .orElse(false);
if (mCapture) {
// Since the user is dragging the bouncer up, set scrimmed to false.
@@ -129,13 +132,17 @@
return true;
}
+ if (!mCentralSurfaces.isPresent()) {
+ return true;
+ }
+
// For consistency, we adopt the expansion definition found in the
// PanelViewController. In this case, expansion refers to the view above the
// bouncer. As that view's expansion shrinks, the bouncer appears. The bouncer
// is fully hidden at full expansion (1) and fully visible when fully collapsed
// (0).
final float screenTravelPercentage = Math.abs(e1.getY() - e2.getY())
- / mCentralSurfaces.getDisplayHeight();
+ / mCentralSurfaces.get().getDisplayHeight();
setPanelExpansion(mBouncerInitiallyShowing
? screenTravelPercentage : 1 - screenTravelPercentage);
return true;
@@ -171,7 +178,7 @@
public BouncerSwipeTouchHandler(
DisplayMetrics displayMetrics,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
- CentralSurfaces centralSurfaces,
+ Optional<CentralSurfaces> centralSurfaces,
NotificationShadeWindowController notificationShadeWindowController,
ValueAnimatorCreator valueAnimatorCreator,
VelocityTrackerFactory velocityTrackerFactory,
@@ -195,7 +202,7 @@
@Override
public void getTouchInitiationRegion(Region region) {
- if (mCentralSurfaces.isBouncerShowing()) {
+ if (mCentralSurfaces.map(CentralSurfaces::isBouncerShowing).orElse(false)) {
region.op(new Rect(0, 0, mDisplayMetrics.widthPixels,
Math.round(
mDisplayMetrics.heightPixels * mBouncerZoneScreenPercentage)),
@@ -306,8 +313,12 @@
}
protected void flingToExpansion(float velocity, float expansion) {
+ if (!mCentralSurfaces.isPresent()) {
+ return;
+ }
+
// The animation utils deal in pixel units, rather than expansion height.
- final float viewHeight = mCentralSurfaces.getDisplayHeight();
+ final float viewHeight = mCentralSurfaces.get().getDisplayHeight();
final float currentHeight = viewHeight * mCurrentExpansion;
final float targetHeight = viewHeight * expansion;
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
index aaa4d9e..c4531b5 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
@@ -42,10 +42,14 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.statusbar.commandline.Command;
+import com.android.systemui.statusbar.commandline.CommandRegistry;
import com.android.systemui.util.settings.SecureSettings;
import java.io.PrintWriter;
+import java.lang.reflect.Field;
import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;
@@ -59,6 +63,10 @@
*
* Flags can be set (or unset) via the following adb command:
*
+ * adb shell cmd statusbar flag <id> <on|off|toggle|erase>
+ *
+ * Alternatively, you can change flags via a broadcast intent:
+ *
* adb shell am broadcast -a com.android.systemui.action.SET_FLAG --ei id <id> [--ez value <0|1>]
*
* To restore a flag back to its default, leave the `--ez value <0|1>` off of the command.
@@ -67,6 +75,7 @@
public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
private static final String TAG = "SysUIFlags";
static final String ALL_FLAGS = "all_flags";
+ private static final String FLAG_COMMAND = "flag";
private final FlagManager mFlagManager;
private final SecureSettings mSecureSettings;
@@ -86,12 +95,15 @@
@Main Resources resources,
DumpManager dumpManager,
@Named(ALL_FLAGS) Map<Integer, Flag<?>> allFlags,
+ CommandRegistry commandRegistry,
IStatusBarService barService) {
mFlagManager = flagManager;
mSecureSettings = secureSettings;
mResources = resources;
mSystemProperties = systemProperties;
mAllFlags = allFlags;
+ mBarService = barService;
+
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_SET_FLAG);
filter.addAction(ACTION_GET_FLAGS);
@@ -100,7 +112,7 @@
context.registerReceiver(mReceiver, filter, null, null,
Context.RECEIVER_EXPORTED_UNAUDITED);
dumpManager.registerDumpable(TAG, this);
- mBarService = barService;
+ commandRegistry.registerCommand(FLAG_COMMAND, FlagCommand::new);
}
@Override
@@ -276,6 +288,31 @@
}
}
+ private void setBooleanFlagInternal(Flag<?> flag, boolean value) {
+ if (flag instanceof BooleanFlag) {
+ setFlagValue(flag.getId(), value, BooleanFlagSerializer.INSTANCE);
+ } else if (flag instanceof ResourceBooleanFlag) {
+ setFlagValue(flag.getId(), value, BooleanFlagSerializer.INSTANCE);
+ } else if (flag instanceof SysPropBooleanFlag) {
+ // Store SysProp flags in SystemProperties where they can read by outside parties.
+ mSystemProperties.setBoolean(((SysPropBooleanFlag) flag).getName(), value);
+ dispatchListenersAndMaybeRestart(flag.getId(),
+ FeatureFlagsDebug.this::restartAndroid);
+ } else {
+ throw new IllegalArgumentException("Unknown flag type");
+ }
+ }
+
+ private void setStringFlagInternal(Flag<?> flag, String value) {
+ if (flag instanceof StringFlag) {
+ setFlagValue(flag.getId(), value, StringFlagSerializer.INSTANCE);
+ } else if (flag instanceof ResourceStringFlag) {
+ setFlagValue(flag.getId(), value, StringFlagSerializer.INSTANCE);
+ } else {
+ throw new IllegalArgumentException("Unknown flag type");
+ }
+ }
+
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -327,24 +364,19 @@
}
Object value = extras.get(EXTRA_VALUE);
- if (flag instanceof BooleanFlag && value instanceof Boolean) {
- setFlagValue(id, (Boolean) value, BooleanFlagSerializer.INSTANCE);
- } else if (flag instanceof ResourceBooleanFlag && value instanceof Boolean) {
- setFlagValue(id, (Boolean) value, BooleanFlagSerializer.INSTANCE);
- } else if (flag instanceof SysPropBooleanFlag && value instanceof Boolean) {
- // Store SysProp flags in SystemProperties where they can read by outside parties.
- mSystemProperties.setBoolean(
- ((SysPropBooleanFlag) flag).getName(), (Boolean) value);
- dispatchListenersAndMaybeRestart(flag.getId(),
- FeatureFlagsDebug.this::restartAndroid);
- } else if (flag instanceof StringFlag && value instanceof String) {
- setFlagValue(id, (String) value, StringFlagSerializer.INSTANCE);
- } else if (flag instanceof ResourceStringFlag && value instanceof String) {
- setFlagValue(id, (String) value, StringFlagSerializer.INSTANCE);
- } else {
+
+ try {
+ if (value instanceof Boolean) {
+ setBooleanFlagInternal(flag, (Boolean) value);
+ } else if (value instanceof String) {
+ setStringFlagInternal(flag, (String) value);
+ } else {
+ throw new IllegalArgumentException("Unknown value type");
+ }
+ } catch (IllegalArgumentException e) {
Log.w(TAG,
- "Unable to set " + id + " of type " + flag.getClass() + " to value of type "
- + (value == null ? null : value.getClass()));
+ "Unable to set " + flag.getId() + " of type " + flag.getClass()
+ + " to value of type " + (value == null ? null : value.getClass()));
}
}
@@ -388,4 +420,153 @@
mStringFlagCache.forEach((key, value) -> pw.println(" sysui_flag_" + key
+ ": [length=" + value.length() + "] \"" + value + "\""));
}
+
+ class FlagCommand implements Command {
+ private final List<String> mOnCommands = List.of("true", "on", "1", "enabled");
+ private final List<String> mOffCommands = List.of("false", "off", "0", "disable");
+
+ @Override
+ public void execute(@NonNull PrintWriter pw, @NonNull List<String> args) {
+ if (args.size() == 0) {
+ pw.println("Error: no flag id supplied");
+ help(pw);
+ pw.println();
+ printKnownFlags(pw);
+ return;
+ }
+
+ if (args.size() > 2) {
+ pw.println("Invalid number of arguments.");
+ help(pw);
+ return;
+ }
+
+ int id = 0;
+ try {
+ id = Integer.parseInt(args.get(0));
+ if (!mAllFlags.containsKey(id)) {
+ pw.println("Unknown flag id: " + id);
+ pw.println();
+ printKnownFlags(pw);
+ return;
+ }
+ } catch (NumberFormatException e) {
+ id = flagNameToId(args.get(0));
+ if (id == 0) {
+ pw.println("Invalid flag. Must an integer id or flag name: " + args.get(0));
+ return;
+ }
+ }
+ Flag<?> flag = mAllFlags.get(id);
+
+ String cmd = "";
+ if (args.size() == 2) {
+ cmd = args.get(1).toLowerCase();
+ }
+
+ if ("erase".equals(cmd) || "reset".equals(cmd)) {
+ eraseFlag(flag);
+ return;
+ }
+
+ boolean newValue = true;
+ if (args.size() == 1 || "toggle".equals(cmd)) {
+ boolean enabled = isBooleanFlagEnabled(flag);
+
+ if (args.size() == 1) {
+ pw.println("Flag " + id + " is " + enabled);
+ return;
+ }
+
+ newValue = !enabled;
+ } else {
+ newValue = mOnCommands.contains(cmd);
+ if (!newValue && !mOffCommands.contains(cmd)) {
+ pw.println("Invalid on/off argument supplied");
+ help(pw);
+ return;
+ }
+ }
+
+ pw.flush(); // Next command will restart sysui, so flush before we do so.
+ setBooleanFlagInternal(flag, newValue);
+ }
+
+ @Override
+ public void help(PrintWriter pw) {
+ pw.println(
+ "Usage: adb shell cmd statusbar flag <id> "
+ + "[true|false|1|0|on|off|enable|disable|toggle|erase|reset]");
+ pw.println("The id can either be a numeric integer or the corresponding field name");
+ pw.println(
+ "If no argument is supplied after the id, the flags runtime value is output");
+ }
+
+ private boolean isBooleanFlagEnabled(Flag<?> flag) {
+ if (flag instanceof BooleanFlag) {
+ return isEnabled((BooleanFlag) flag);
+ } else if (flag instanceof ResourceBooleanFlag) {
+ return isEnabled((ResourceBooleanFlag) flag);
+ } else if (flag instanceof SysPropFlag) {
+ return isEnabled((SysPropBooleanFlag) flag);
+ }
+
+ return false;
+ }
+
+ private int flagNameToId(String flagName) {
+ List<Field> fields = Flags.getFlagFields();
+ for (Field field : fields) {
+ if (flagName.equals(field.getName())) {
+ return fieldToId(field);
+ }
+ }
+
+ return 0;
+ }
+
+ private int fieldToId(Field field) {
+ try {
+ Flag<?> flag = (Flag<?>) field.get(null);
+ return flag.getId();
+ } catch (IllegalAccessException e) {
+ // no-op
+ }
+
+ return 0;
+ }
+
+ private void printKnownFlags(PrintWriter pw) {
+ List<Field> fields = Flags.getFlagFields();
+
+ int longestFieldName = 0;
+ for (Field field : fields) {
+ longestFieldName = Math.max(longestFieldName, field.getName().length());
+ }
+
+ pw.println("Known Flags:");
+ pw.print("Flag Name");
+ for (int i = 0; i < longestFieldName - "Flag Name".length() + 1; i++) {
+ pw.print(" ");
+ }
+ pw.println("ID Enabled?");
+ for (int i = 0; i < longestFieldName; i++) {
+ pw.print("=");
+ }
+ pw.println(" ==== ========");
+ for (Field field : fields) {
+ int id = fieldToId(field);
+ if (id == 0 || !mAllFlags.containsKey(id)) {
+ continue;
+ }
+ pw.print(field.getName());
+ int fieldWidth = field.getName().length();
+ for (int i = 0; i < longestFieldName - fieldWidth + 1; i++) {
+ pw.print(" ");
+ }
+ pw.printf("%-4d ", id);
+ pw.println(isBooleanFlagEnabled(mAllFlags.get(id)));
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 44580aa..afa7d5e 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -20,7 +20,9 @@
import com.android.systemui.R;
import java.lang.reflect.Field;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
/**
@@ -182,19 +184,16 @@
if (sFlagMap != null) {
return sFlagMap;
}
+
Map<Integer, Flag<?>> flags = new HashMap<>();
+ List<Field> flagFields = getFlagFields();
- Field[] fields = Flags.class.getFields();
-
- for (Field field : fields) {
- Class<?> t = field.getType();
- if (Flag.class.isAssignableFrom(t)) {
- try {
- Flag<?> flag = (Flag<?>) field.get(null);
- flags.put(flag.getId(), flag);
- } catch (IllegalAccessException e) {
- // no-op
- }
+ for (Field field : flagFields) {
+ try {
+ Flag<?> flag = (Flag<?>) field.get(null);
+ flags.put(flag.getId(), flag);
+ } catch (IllegalAccessException e) {
+ // no-op
}
}
@@ -202,6 +201,20 @@
return sFlagMap;
}
+
+ static List<Field> getFlagFields() {
+ Field[] fields = Flags.class.getFields();
+ List<Field> result = new ArrayList<>();
+
+ for (Field field : fields) {
+ Class<?> t = field.getType();
+ if (Flag.class.isAssignableFrom(t)) {
+ result.add(field);
+ }
+ }
+
+ return result;
+ }
// | . . . . . . . . . . . . . . . . . . . |
// | |
// \_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/
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 71dfa74..165af13 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -25,6 +25,7 @@
import com.android.keyguard.KeyguardDisplayManager;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardViewController;
+import com.android.keyguard.ViewMediatorCallback;
import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent;
import com.android.keyguard.dagger.KeyguardStatusBarViewComponent;
import com.android.keyguard.dagger.KeyguardStatusViewComponent;
@@ -127,4 +128,10 @@
notificationShadeWindowController,
activityLaunchAnimator);
}
+
+ /** */
+ @Provides
+ public ViewMediatorCallback providesViewMediatorCallback(KeyguardViewMediator viewMediator) {
+ return viewMediator.getViewMediatorCallback();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/ColorSchemeTransition.kt b/packages/SystemUI/src/com/android/systemui/media/ColorSchemeTransition.kt
index 8f0305f..2ae1806 100644
--- a/packages/SystemUI/src/com/android/systemui/media/ColorSchemeTransition.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/ColorSchemeTransition.kt
@@ -85,12 +85,13 @@
*/
class ColorSchemeTransition internal constructor(
private val context: Context,
- bgColor: Int,
mediaViewHolder: MediaViewHolder,
colorTransitionFactory: ColorTransitionFactory
) {
- constructor(context: Context, bgColor: Int, mediaViewHolder: MediaViewHolder) :
- this(context, bgColor, mediaViewHolder, ::ColorTransition)
+ constructor(context: Context, mediaViewHolder: MediaViewHolder) :
+ this(context, mediaViewHolder, ::ColorTransition)
+
+ val bgColor = context.getColor(com.android.systemui.R.color.material_dynamic_secondary95)
val surfaceColor = colorTransitionFactory(
bgColor,
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index 8e81831..ca25a18 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -127,7 +127,6 @@
private val visualStabilityCallback: OnReorderingAllowedListener
private var needsReordering: Boolean = false
private var keysNeedRemoval = mutableSetOf<String>()
- private var bgColor = getBackgroundColor()
protected var shouldScrollToActivePlayer: Boolean = false
private var isRtl: Boolean = false
set(value) {
@@ -488,7 +487,7 @@
val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT)
newRecs.recommendationViewHolder?.recommendations?.setLayoutParams(lp)
- newRecs.bindRecommendation(data.copy(backgroundColor = bgColor))
+ newRecs.bindRecommendation(data)
val curVisibleMediaKey = MediaPlayerData.playerKeys()
.elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex)
MediaPlayerData.addMediaRecommendation(key, data, newRecs, shouldPrioritize, systemClock)
@@ -534,7 +533,6 @@
}
private fun recreatePlayers() {
- bgColor = getBackgroundColor()
pageIndicator.tintList = ColorStateList.valueOf(R.color.material_dynamic_neutral_variant80)
MediaPlayerData.mediaData().forEach { (key, data, isSsMediaRec) ->
@@ -554,10 +552,6 @@
}
}
- private fun getBackgroundColor(): Int {
- return context.getColor(R.color.material_dynamic_secondary95)
- }
-
private fun updatePageIndicator() {
val numPages = mediaContent.getChildCount()
pageIndicator.setNumPages(numPages)
@@ -904,7 +898,6 @@
private val EMPTY = MediaData(
userId = -1,
initialized = false,
- backgroundColor = 0,
app = null,
appIcon = null,
artist = null,
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index a264afd..915c3f2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -60,6 +60,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.InstanceId;
+import com.android.settingslib.Utils;
import com.android.settingslib.widget.AdaptiveIcon;
import com.android.systemui.ActivityIntentHelper;
import com.android.systemui.R;
@@ -100,8 +101,7 @@
+ ".android.apps.gsa.staticplugins.opa.smartspace.ExportedSmartspaceTrampolineActivity";
private static final String EXTRAS_SMARTSPACE_INTENT =
"com.google.android.apps.gsa.smartspace.extra.SMARTSPACE_INTENT";
- private static final int MEDIA_RECOMMENDATION_ITEMS_PER_ROW = 3;
- private static final int MEDIA_RECOMMENDATION_MAX_NUM = 6;
+ private static final int MEDIA_RECOMMENDATION_MAX_NUM = 3;
private static final String KEY_SMARTSPACE_ARTIST_NAME = "artist_name";
private static final String KEY_SMARTSPACE_OPEN_IN_FOREGROUND = "KEY_OPEN_IN_FOREGROUND";
private static final String KEY_SMARTSPACE_APP_NAME = "KEY_SMARTSPACE_APP_NAME";
@@ -151,7 +151,6 @@
private MediaSession.Token mToken;
private MediaController mController;
private Lazy<MediaDataManager> mMediaDataManagerLazy;
- private int mBackgroundColor;
// Uid for the media app.
protected int mUid = Process.INVALID_UID;
private int mSmartspaceMediaItemsCount;
@@ -344,8 +343,7 @@
AnimatorSet exit = loadAnimator(R.anim.media_metadata_exit,
Interpolators.EMPHASIZED_ACCELERATE, titleText, artistText);
- mColorSchemeTransition = new ColorSchemeTransition(
- mContext, mBackgroundColor, mMediaViewHolder);
+ mColorSchemeTransition = new ColorSchemeTransition(mContext, mMediaViewHolder);
mMetadataAnimationHandler = new MetadataAnimationHandler(exit, enter);
}
@@ -410,7 +408,6 @@
}
mInstanceId = data.getInstanceId();
- mBackgroundColor = data.getBackgroundColor();
if (mToken == null || !mToken.equals(token)) {
mToken = token;
}
@@ -486,7 +483,7 @@
Drawable icon = device.getIcon();
if (icon instanceof AdaptiveIcon) {
AdaptiveIcon aIcon = (AdaptiveIcon) icon;
- aIcon.setBackgroundColor(mBackgroundColor);
+ aIcon.setBackgroundColor(mColorSchemeTransition.getBgColor());
iconView.setImageDrawable(aIcon);
} else {
iconView.setImageDrawable(icon);
@@ -957,11 +954,11 @@
}
mSmartspaceId = SmallHash.hash(data.getTargetId());
- mBackgroundColor = data.getBackgroundColor();
mPackageName = data.getPackageName();
mInstanceId = data.getInstanceId();
TransitionLayout recommendationCard = mRecommendationViewHolder.getRecommendations();
- recommendationCard.setBackgroundTintList(ColorStateList.valueOf(mBackgroundColor));
+ recommendationCard.setBackgroundTintList(
+ Utils.getColorAttr(mContext, com.android.internal.R.attr.colorSurface));
List<SmartspaceAction> mediaRecommendationList = data.getRecommendations();
if (mediaRecommendationList == null || mediaRecommendationList.isEmpty()) {
@@ -1001,11 +998,6 @@
appName = packageManager.getApplicationLabel(applicationInfo);
}
}
- // Set the app name as card's title.
- if (!TextUtils.isEmpty(appName)) {
- TextView headerTitleText = mRecommendationViewHolder.getCardText();
- headerTitleText.setText(appName);
- }
// Set up media rec card's tap action if applicable.
setSmartspaceRecItemOnClickListener(recommendationCard, data.getCardAction(),
@@ -1016,11 +1008,6 @@
List<ImageView> mediaCoverItems = mRecommendationViewHolder.getMediaCoverItems();
List<ViewGroup> mediaCoverContainers = mRecommendationViewHolder.getMediaCoverContainers();
- List<Integer> mediaCoverItemsResIds = mRecommendationViewHolder.getMediaCoverItemsResIds();
- List<Integer> mediaCoverContainersResIds =
- mRecommendationViewHolder.getMediaCoverContainersResIds();
- ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();
- ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout();
int mediaRecommendationNum = Math.min(mediaRecommendationList.size(),
MEDIA_RECOMMENDATION_MAX_NUM);
int uiComponentIndex = 0;
@@ -1065,21 +1052,28 @@
recommendation.getTitle(), artistName, appName));
}
- if (uiComponentIndex < MEDIA_RECOMMENDATION_ITEMS_PER_ROW) {
- setVisibleAndAlpha(collapsedSet,
- mediaCoverItemsResIds.get(uiComponentIndex), true);
- setVisibleAndAlpha(collapsedSet,
- mediaCoverContainersResIds.get(uiComponentIndex), true);
- } else {
- setVisibleAndAlpha(collapsedSet,
- mediaCoverItemsResIds.get(uiComponentIndex), false);
- setVisibleAndAlpha(collapsedSet,
- mediaCoverContainersResIds.get(uiComponentIndex), false);
- }
- setVisibleAndAlpha(expandedSet,
- mediaCoverItemsResIds.get(uiComponentIndex), true);
- setVisibleAndAlpha(expandedSet,
- mediaCoverContainersResIds.get(uiComponentIndex), true);
+
+ // Set up title
+ CharSequence title = recommendation.getTitle();
+ TextView titleView =
+ mRecommendationViewHolder.getMediaTitles().get(uiComponentIndex);
+ titleView.setText(title);
+ titleView.setTextColor(Utils.getColorAttrDefaultColor(
+ mContext, com.android.internal.R.attr.textColorPrimary));
+ // TODO(b/223603970): If none of them have titles, should we then hide the views?
+
+ // Set up subtitle
+ CharSequence subtitle = recommendation.getSubtitle();
+ TextView subtitleView =
+ mRecommendationViewHolder.getMediaSubtitles().get(uiComponentIndex);
+ // It would look awkward to show a subtitle if we don't have a title.
+ boolean shouldShowSubtitleText = !TextUtils.isEmpty(title);
+ CharSequence subtitleText = shouldShowSubtitleText ? subtitle : "";
+ subtitleView.setText(subtitleText);
+ subtitleView.setTextColor(Utils.getColorAttrDefaultColor(
+ mContext, com.android.internal.R.attr.textColorSecondary));
+ // TODO(b/223603970): If none of them have subtitles, should we then hide the views?
+
uiComponentIndex++;
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
index f6d531b..d04ec40 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
@@ -27,7 +27,6 @@
data class MediaData(
val userId: Int,
val initialized: Boolean = false,
- val backgroundColor: Int,
/**
* App name that will be displayed on the player.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 0d65514..b2751ce 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -85,7 +85,6 @@
private val LOADING = MediaData(
userId = -1,
initialized = false,
- backgroundColor = 0,
app = null,
appIcon = null,
artist = null,
@@ -111,7 +110,6 @@
cardAction = null,
recommendations = emptyList(),
dismissIntent = null,
- backgroundColor = 0,
headphoneConnectionTimeMillis = 0,
instanceId = InstanceId.fakeInstanceId(-1))
@@ -177,7 +175,6 @@
private val themeText = com.android.settingslib.Utils.getColorAttr(context,
com.android.internal.R.attr.textColorPrimary).defaultColor
- private val bgColor = context.getColor(R.color.material_dynamic_secondary95)
// Internal listeners are part of the internal pipeline. External listeners (those registered
// with [MediaDeviceManager.addListener]) receive events after they have propagated through
@@ -591,7 +588,7 @@
val mediaAction = getResumeMediaAction(resumeAction)
val lastActive = systemClock.elapsedRealtime()
foregroundExecutor.execute {
- onMediaDataLoaded(packageName, null, MediaData(userId, true, bgColor, appName,
+ onMediaDataLoaded(packageName, null, MediaData(userId, true, appName,
null, desc.subtitle, desc.title, artworkIcon, listOf(mediaAction), listOf(0),
MediaButton(playOrPause = mediaAction), packageName, token, appIntent,
device = null, active = false,
@@ -601,14 +598,17 @@
}
}
- private fun loadMediaDataInBg(
+ fun loadMediaDataInBg(
key: String,
sbn: StatusBarNotification,
oldKey: String?,
logEvent: Boolean = false
) {
- val token = sbn.notification.extras.getParcelable(Notification.EXTRA_MEDIA_SESSION)
- as MediaSession.Token?
+ val token = sbn.notification.extras.getParcelable(
+ Notification.EXTRA_MEDIA_SESSION, MediaSession.Token::class.java)
+ if (token == null) {
+ return
+ }
val mediaController = mediaControllerFactory.create(token)
val metadata = mediaController.metadata
@@ -655,8 +655,8 @@
val extras = sbn.notification.extras
val deviceName = extras.getCharSequence(Notification.EXTRA_MEDIA_REMOTE_DEVICE, null)
val deviceIcon = extras.getInt(Notification.EXTRA_MEDIA_REMOTE_ICON, -1)
- val deviceIntent = extras.getParcelable(Notification.EXTRA_MEDIA_REMOTE_INTENT)
- as PendingIntent?
+ val deviceIntent = extras.getParcelable(
+ Notification.EXTRA_MEDIA_REMOTE_INTENT, PendingIntent::class.java)
Log.d(TAG, "$key is RCN for $deviceName")
if (deviceName != null && deviceIcon > -1) {
@@ -710,7 +710,7 @@
val resumeAction: Runnable? = mediaEntries[key]?.resumeAction
val hasCheckedForResume = mediaEntries[key]?.hasCheckedForResume == true
val active = mediaEntries[key]?.active ?: true
- onMediaDataLoaded(key, oldKey, MediaData(sbn.normalizedUserId, true, bgColor, app,
+ onMediaDataLoaded(key, oldKey, MediaData(sbn.normalizedUserId, true, app,
smallIcon, artist, song, artWorkIcon, actionIcons, actionsToShowCollapsed,
semanticActions, sbn.packageName, token, notif.contentIntent, device,
active, resumeAction = resumeAction, playbackLocation = playbackLocation,
@@ -1227,7 +1227,6 @@
cardAction = target.baseAction,
recommendations = target.iconGrid,
dismissIntent = dismissIntent,
- backgroundColor = 0,
headphoneConnectionTimeMillis = target.creationTimeMillis,
instanceId = logger.getNewInstanceId())
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/RecommendationViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/RecommendationViewHolder.kt
index c0f79d5..a839840 100644
--- a/packages/SystemUI/src/com/android/systemui/media/RecommendationViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/RecommendationViewHolder.kt
@@ -31,35 +31,26 @@
// Recommendation screen
val cardIcon = itemView.requireViewById<ImageView>(R.id.recommendation_card_icon)
- val cardText = itemView.requireViewById<TextView>(R.id.recommendation_card_text)
val mediaCoverItems = listOf<ImageView>(
itemView.requireViewById(R.id.media_cover1),
itemView.requireViewById(R.id.media_cover2),
- itemView.requireViewById(R.id.media_cover3),
- itemView.requireViewById(R.id.media_cover4),
- itemView.requireViewById(R.id.media_cover5),
- itemView.requireViewById(R.id.media_cover6))
+ itemView.requireViewById(R.id.media_cover3)
+ )
val mediaCoverContainers = listOf<ViewGroup>(
itemView.requireViewById(R.id.media_cover1_container),
itemView.requireViewById(R.id.media_cover2_container),
- itemView.requireViewById(R.id.media_cover3_container),
- itemView.requireViewById(R.id.media_cover4_container),
- itemView.requireViewById(R.id.media_cover5_container),
- itemView.requireViewById(R.id.media_cover6_container))
- val mediaCoverItemsResIds = listOf<Int>(
- R.id.media_cover1,
- R.id.media_cover2,
- R.id.media_cover3,
- R.id.media_cover4,
- R.id.media_cover5,
- R.id.media_cover6)
- val mediaCoverContainersResIds = listOf<Int>(
- R.id.media_cover1_container,
- R.id.media_cover2_container,
- R.id.media_cover3_container,
- R.id.media_cover4_container,
- R.id.media_cover5_container,
- R.id.media_cover6_container)
+ itemView.requireViewById(R.id.media_cover3_container)
+ )
+ val mediaTitles: List<TextView> = listOf(
+ itemView.requireViewById(R.id.media_title1),
+ itemView.requireViewById(R.id.media_title2),
+ itemView.requireViewById(R.id.media_title3)
+ )
+ val mediaSubtitles: List<TextView> = listOf(
+ itemView.requireViewById(R.id.media_subtitle1),
+ itemView.requireViewById(R.id.media_subtitle2),
+ itemView.requireViewById(R.id.media_subtitle3)
+ )
// Settings/Guts screen
val longPressText = itemView.requireViewById<TextView>(R.id.remove_text)
@@ -107,19 +98,12 @@
// Res Ids for the control components on the recommendation view.
val controlsIds = setOf(
R.id.recommendation_card_icon,
- R.id.recommendation_card_text,
R.id.media_cover1,
R.id.media_cover2,
R.id.media_cover3,
- R.id.media_cover4,
- R.id.media_cover5,
- R.id.media_cover6,
R.id.media_cover1_container,
R.id.media_cover2_container,
R.id.media_cover3_container,
- R.id.media_cover4_container,
- R.id.media_cover5_container,
- R.id.media_cover6_container
)
// Res Ids for the components on the guts panel.
diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
index c9d300b..60ef85d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
@@ -89,6 +89,7 @@
holder.seekBar.thumb.alpha = if (data.seekAvailable) 255 else 0
holder.seekBar.isEnabled = data.seekAvailable
progressDrawable?.animate = data.playing && !data.scrubbing
+ progressDrawable?.transitionEnabled = !data.seekAvailable
if (holder.seekBar.maxHeight != seekBarEnabledMaxHeight) {
holder.seekBar.maxHeight = seekBarEnabledMaxHeight
diff --git a/packages/SystemUI/src/com/android/systemui/media/SmartspaceMediaData.kt b/packages/SystemUI/src/com/android/systemui/media/SmartspaceMediaData.kt
index e161ea7..930c5a8 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SmartspaceMediaData.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SmartspaceMediaData.kt
@@ -51,10 +51,6 @@
*/
val dismissIntent: Intent?,
/**
- * View's background color.
- */
- val backgroundColor: Int,
- /**
* The timestamp in milliseconds that headphone is connected.
*/
val headphoneConnectionTimeMillis: Long,
diff --git a/packages/SystemUI/src/com/android/systemui/media/SquigglyProgress.kt b/packages/SystemUI/src/com/android/systemui/media/SquigglyProgress.kt
index fbd17d7..88f6f3d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SquigglyProgress.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SquigglyProgress.kt
@@ -5,13 +5,15 @@
import android.animation.ValueAnimator
import android.content.res.ColorStateList
import android.graphics.Canvas
-import android.graphics.Color
import android.graphics.ColorFilter
import android.graphics.Paint
import android.graphics.Path
import android.graphics.PixelFormat
import android.graphics.drawable.Drawable
import android.os.SystemClock
+import android.util.MathUtils.lerp
+import android.util.MathUtils.lerpInv
+import android.util.MathUtils.lerpInvSat
import androidx.annotation.VisibleForTesting
import com.android.internal.graphics.ColorUtils
import com.android.systemui.animation.Interpolators
@@ -34,6 +36,13 @@
private var phaseOffset = 0f
private var lastFrameTime = -1L
+ /* distance over which amplitude drops to zero, measured in wavelengths */
+ private val transitionPeriods = 1.5f
+ /* wave endpoint as percentage of bar when play position is zero */
+ private val minWaveEndpoint = 0.2f
+ /* wave endpoint as percentage of bar when play position matches wave endpoint */
+ private val matchedWaveEndpoint = 0.6f
+
// Horizontal length of the sine wave
var waveLength = 0f
// Height of each peak of the sine wave
@@ -51,6 +60,12 @@
linePaint.strokeWidth = value
}
+ var transitionEnabled = true
+ set(value) {
+ field = value
+ invalidateSelf()
+ }
+
init {
wavePaint.strokeCap = Paint.Cap.ROUND
linePaint.strokeCap = Paint.Cap.ROUND
@@ -95,57 +110,90 @@
if (animate) {
invalidateSelf()
val now = SystemClock.uptimeMillis()
- phaseOffset -= (now - lastFrameTime) / 1000f * phaseSpeed
+ phaseOffset += (now - lastFrameTime) / 1000f * phaseSpeed
phaseOffset %= waveLength
lastFrameTime = now
}
- val totalProgressPx = (bounds.width() * (level / 10_000f))
+ val progress = level / 10_000f
+ val totalProgressPx = bounds.width() * progress
+ val waveProgressPx = bounds.width() * (
+ if (!transitionEnabled || progress > matchedWaveEndpoint) progress else
+ lerp(minWaveEndpoint, matchedWaveEndpoint, lerpInv(0f, matchedWaveEndpoint, progress)))
+
+ // Build Wiggly Path
+ val waveStart = -phaseOffset
+ val waveEnd = waveProgressPx
+ val transitionLength = if (transitionEnabled) transitionPeriods * waveLength else 0.01f
+
+ // helper function, computes amplitude for wave segment
+ val computeAmplitude: (Float, Float) -> Float = { x, sign ->
+ sign * heightFraction * lineAmplitude *
+ lerpInvSat(waveEnd, waveEnd - transitionLength, x)
+ }
+
+ var currentX = waveEnd
+ var waveSign = if (phaseOffset < waveLength / 2) 1f else -1f
+ path.rewind()
+
+ // Draw flat line from end to wave endpoint
+ path.moveTo(bounds.width().toFloat(), 0f)
+ path.lineTo(waveEnd, 0f)
+
+ // First wave has shortened wavelength
+ // approx quarter wave gets us to first wave peak
+ // shouldn't be big enough to notice it's not a sin wave
+ currentX -= phaseOffset % (waveLength / 2)
+ val controlRatio = 0.25f
+ var currentAmp = computeAmplitude(currentX, waveSign)
+ path.cubicTo(
+ waveEnd, currentAmp * controlRatio,
+ lerp(currentX, waveEnd, controlRatio), currentAmp,
+ currentX, currentAmp)
+
+ // Other waves have full wavelength
+ val dist = -1 * waveLength / 2f
+ while (currentX > waveStart) {
+ waveSign = -waveSign
+ val nextX = currentX + dist
+ val midX = currentX + dist / 2
+ val nextAmp = computeAmplitude(nextX, waveSign)
+ path.cubicTo(
+ midX, currentAmp,
+ midX, nextAmp,
+ nextX, nextAmp)
+ currentAmp = nextAmp
+ currentX = nextX
+ }
+
+ // Draw path; clip to progress position
canvas.save()
canvas.translate(bounds.left.toFloat(), bounds.centerY().toFloat())
- // Clip drawing, so we stop at the thumb
canvas.clipRect(
0f,
-lineAmplitude - strokeWidth,
totalProgressPx,
lineAmplitude + strokeWidth)
-
- // The squiggly line
- val start = phaseOffset
- var currentX = start
- var waveSign = 1f
- path.rewind()
- path.moveTo(start, lineAmplitude * heightFraction)
- while (currentX < totalProgressPx) {
- val nextX = currentX + waveLength / 2f
- val nextWaveSign = waveSign * -1
- path.cubicTo(
- currentX + waveLength / 4f, lineAmplitude * waveSign * heightFraction,
- nextX - waveLength / 4f, lineAmplitude * nextWaveSign * heightFraction,
- nextX, lineAmplitude * nextWaveSign * heightFraction)
- currentX = nextX
- waveSign = nextWaveSign
- }
- wavePaint.style = Paint.Style.STROKE
canvas.drawPath(path, wavePaint)
canvas.restore()
+ // Draw path; clip between progression position & far edge
+ canvas.save()
+ canvas.translate(bounds.left.toFloat(), bounds.centerY().toFloat())
+ canvas.clipRect(
+ totalProgressPx,
+ -lineAmplitude - strokeWidth,
+ bounds.width().toFloat(),
+ lineAmplitude + strokeWidth)
+ canvas.drawPath(path, linePaint)
+ canvas.restore()
+
// Draw round line cap at the beginning of the wave
- val startAmp = cos(abs(phaseOffset) / waveLength * TWO_PI)
- val p = Paint()
- p.color = Color.WHITE
+ val startAmp = cos(abs(waveEnd - phaseOffset) / waveLength * TWO_PI)
canvas.drawPoint(
bounds.left.toFloat(),
bounds.centerY() + startAmp * lineAmplitude * heightFraction,
wavePaint)
-
- // Draw continuous line, to the right of the thumb
- canvas.drawLine(
- bounds.left.toFloat() + totalProgressPx,
- bounds.centerY().toFloat(),
- bounds.width().toFloat(),
- bounds.centerY().toFloat(),
- linePaint)
}
override fun getOpacity(): Int {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index 0edadcc..73ab66e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -117,6 +117,7 @@
}
mCheckBox.setVisibility(View.GONE);
mStatusIcon.setVisibility(View.GONE);
+ mEndTouchArea.setVisibility(View.GONE);
mContainerLayout.setOnClickListener(null);
mTitleText.setTextColor(mController.getColorItemContent());
mSubTitleText.setTextColor(mController.getColorItemContent());
@@ -168,12 +169,16 @@
setSingleLineLayout(getItemTitle(device), true /* bFocused */,
true /* showSeekBar */,
false /* showProgressBar */, false /* showStatus */);
+ mCheckBox.setOnCheckedChangeListener(null);
mCheckBox.setVisibility(View.VISIBLE);
mCheckBox.setChecked(true);
- mSeekBar.setOnClickListener(null);
- mSeekBar.setOnClickListener(v -> onGroupActionTriggered(false, device));
+ mCheckBox.setOnCheckedChangeListener(
+ (buttonView, isChecked) -> onGroupActionTriggered(false, device));
setCheckBoxColor(mCheckBox, mController.getColorItemContent());
initSeekbar(device);
+ mEndTouchArea.setVisibility(View.VISIBLE);
+ mEndTouchArea.setOnClickListener(null);
+ mEndTouchArea.setOnClickListener((v) -> mCheckBox.performClick());
} else if (!mController.hasAdjustVolumeUserRestriction() && currentlyConnected) {
mStatusIcon.setImageDrawable(
mContext.getDrawable(R.drawable.media_output_status_check));
@@ -185,8 +190,12 @@
initSeekbar(device);
mCurrentActivePosition = position;
} else if (isDeviceIncluded(mController.getSelectableMediaDevice(), device)) {
+ mCheckBox.setOnCheckedChangeListener(null);
mCheckBox.setVisibility(View.VISIBLE);
mCheckBox.setChecked(false);
+ mCheckBox.setOnCheckedChangeListener(
+ (buttonView, isChecked) -> onGroupActionTriggered(true, device));
+ mEndTouchArea.setVisibility(View.VISIBLE);
mContainerLayout.setOnClickListener(v -> onGroupActionTriggered(true, device));
setCheckBoxColor(mCheckBox, mController.getColorItemContent());
setSingleLineLayout(getItemTitle(device), false /* bFocused */,
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
index 5c536d4..9dc29bd 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -144,6 +144,7 @@
final LinearLayout mTwoLineLayout;
final ImageView mStatusIcon;
final CheckBox mCheckBox;
+ final LinearLayout mEndTouchArea;
private String mDeviceId;
MediaDeviceBaseViewHolder(View view) {
@@ -159,6 +160,7 @@
mSeekBar = view.requireViewById(R.id.volume_seekbar);
mStatusIcon = view.requireViewById(R.id.media_output_item_status);
mCheckBox = view.requireViewById(R.id.check_box);
+ mEndTouchArea = view.requireViewById(R.id.end_action_area);
}
void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin, int position) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSeekbar.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSeekbar.java
deleted file mode 100644
index 72f308e..0000000
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputSeekbar.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.media.dialog;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.widget.SeekBar;
-
-/**
- * Customized seekbar used by MediaOutputDialog, which only changes progress when dragging,
- * otherwise performs click.
- */
-public class MediaOutputSeekbar extends SeekBar {
- private int mLastDownPosition = -1;
-
- public MediaOutputSeekbar(Context context) {
- super(context);
- }
-
- public MediaOutputSeekbar(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
- mLastDownPosition = Math.round(event.getX());
- } else if (event.getAction() == MotionEvent.ACTION_UP) {
- if (mLastDownPosition == event.getX()) {
- performClick();
- return true;
- }
- mLastDownPosition = -1;
- }
- return super.onTouchEvent(event);
- }
-
- @Override
- public boolean performClick() {
- return super.performClick();
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
index cc37ef4..13340b7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
@@ -234,6 +234,7 @@
val dialog = SystemUIDialog(context)
dialog.setTitle(R.string.fgs_manager_dialog_title)
+ dialog.setMessage(R.string.fgs_manager_dialog_message)
val dialogContext = dialog.context
@@ -241,7 +242,9 @@
recyclerView.layoutManager = LinearLayoutManager(dialogContext)
recyclerView.adapter = appListAdapter
- dialog.setView(recyclerView)
+ val topSpacing = dialogContext.resources
+ .getDimensionPixelSize(R.dimen.fgs_manager_list_top_spacing)
+ dialog.setView(recyclerView, 0, topSpacing, 0, 0)
this.dialog = dialog
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 76ec6bd..f87cb29 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -612,7 +612,7 @@
} else if (progress > 0 && view.getVisibility() != View.VISIBLE) {
view.setVisibility((View.VISIBLE));
}
- float alpha = mQSPanelController.bouncerInTransit()
+ float alpha = mQSPanelController.isBouncerInTransit()
? BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(progress)
: ShadeInterpolation.getContentAlpha(progress);
view.setAlpha(alpha);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
index 5670836..851307a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
@@ -254,8 +254,8 @@
*
* @return if bouncer is in transit
*/
- public boolean bouncerInTransit() {
- return mStatusBarKeyguardViewManager.bouncerIsInTransit();
+ public boolean isBouncerInTransit() {
+ return mStatusBarKeyguardViewManager.isBouncerInTransit();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ReduceBrightColorsController.java b/packages/SystemUI/src/com/android/systemui/qs/ReduceBrightColorsController.java
index 42d603e..39d081d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ReduceBrightColorsController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/ReduceBrightColorsController.java
@@ -26,6 +26,7 @@
import androidx.annotation.NonNull;
+import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.policy.CallbackController;
@@ -38,6 +39,7 @@
/**
* @hide
*/
+@SysUISingleton
public class ReduceBrightColorsController implements
CallbackController<ReduceBrightColorsController.Listener> {
private final ColorDisplayManager mManager;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
index 8921e95..8ca095d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
@@ -58,6 +58,7 @@
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
import com.android.settingslib.Utils;
+import com.android.settingslib.wifi.WifiEnterpriseRestrictionUtils;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.accessibility.floatingmenu.AnnotationLinkSpan;
@@ -136,6 +137,7 @@
private Drawable mBackgroundOff = null;
private int mDefaultDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private boolean mCanConfigMobileData;
+ private boolean mCanChangeWifiState;
// Wi-Fi entries
private int mWifiNetworkHeight;
@@ -180,6 +182,7 @@
mWifiManager = mInternetDialogController.getWifiManager();
mCanConfigMobileData = canConfigMobileData;
mCanConfigWifi = canConfigWifi;
+ mCanChangeWifiState = WifiEnterpriseRestrictionUtils.isChangeWifiStateAllowed(context);
mKeyguard = keyguardStateController;
mUiEventLogger = uiEventLogger;
@@ -449,6 +452,14 @@
}
mTurnWifiOnLayout.setBackground(
(isDeviceLocked && mConnectedWifiEntry != null) ? mBackgroundOn : null);
+
+ if (!mCanChangeWifiState && mWiFiToggle.isEnabled()) {
+ mWiFiToggle.setEnabled(false);
+ mWifiToggleTitleText.setEnabled(false);
+ final TextView summaryText = mDialogView.requireViewById(R.id.wifi_toggle_summary);
+ summaryText.setEnabled(false);
+ summaryText.setVisibility(View.VISIBLE);
+ }
}
@MainThread
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 83138f0..551e8b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -502,8 +502,8 @@
private void updateLockScreenTrustMsg(int userId, CharSequence trustGrantedIndication,
CharSequence trustManagedIndication) {
- if (!TextUtils.isEmpty(trustGrantedIndication)
- && mKeyguardUpdateMonitor.getUserHasTrust(userId)) {
+ final boolean userHasTrust = mKeyguardUpdateMonitor.getUserHasTrust(userId);
+ if (!TextUtils.isEmpty(trustGrantedIndication) && userHasTrust) {
mRotateTextViewController.updateIndication(
INDICATION_TYPE_TRUST,
new KeyguardIndication.Builder()
@@ -513,7 +513,7 @@
false);
} else if (!TextUtils.isEmpty(trustManagedIndication)
&& mKeyguardUpdateMonitor.getUserTrustIsManaged(userId)
- && !mKeyguardUpdateMonitor.getUserHasTrust(userId)) {
+ && !userHasTrust) {
mRotateTextViewController.updateIndication(
INDICATION_TYPE_TRUST,
new KeyguardIndication.Builder()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index f15df8e..c1ea6bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -72,6 +72,9 @@
dumpManager: DumpManager
) : Dumpable {
private var pulseHeight: Float = 0f
+ @get:VisibleForTesting
+ var fractionToShade: Float = 0f
+ private set
private var useSplitShade: Boolean = false
private lateinit var nsslController: NotificationStackScrollLayoutController
lateinit var notificationPanelController: NotificationPanelViewController
@@ -405,9 +408,9 @@
if (field != value || forceApplyAmount) {
field = value
if (!nsslController.isInLockedDownShade() || field == 0f || forceApplyAmount) {
- val notificationShelfProgress =
+ fractionToShade =
MathUtils.saturate(dragDownAmount / notificationShelfTransitionDistance)
- nsslController.setTransitionToFullShadeAmount(notificationShelfProgress)
+ nsslController.setTransitionToFullShadeAmount(fractionToShade)
qSDragProgress = MathUtils.saturate(dragDownAmount / qsTransitionDistance)
qS.setTransitionToFullShadeAmount(field, qSDragProgress)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 241a745..76f9db4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -454,7 +454,7 @@
* update this manager's internal state.
* @return whether the current MediaMetadata changed (and needs to be announced to listeners).
*/
- private boolean findPlayingMediaNotification(
+ boolean findPlayingMediaNotification(
@NonNull Collection<NotificationEntry> allNotifications) {
boolean metaDataChanged = false;
// Promote the media notification with a controller in 'playing' state, if any.
@@ -465,7 +465,7 @@
if (notif.isMediaNotification()) {
final MediaSession.Token token =
entry.getSbn().getNotification().extras.getParcelable(
- Notification.EXTRA_MEDIA_SESSION);
+ Notification.EXTRA_MEDIA_SESSION, MediaSession.Token.class);
if (token != null) {
MediaController aController = new MediaController(mContext, token);
if (PlaybackState.STATE_PLAYING
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 633786f..afce945 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -85,9 +85,6 @@
private NotificationShelfController mController;
private float mActualWidth = -1;
- /** Fraction of lockscreen to shade animation (on lockscreen swipe down). */
- private float mFractionToShade;
-
public NotificationShelf(Context context, AttributeSet attrs) {
super(context, attrs);
}
@@ -234,13 +231,6 @@
}
/**
- * @param fractionToShade Fraction of lockscreen to shade transition
- */
- public void setFractionToShade(float fractionToShade) {
- mFractionToShade = fractionToShade;
- }
-
- /**
* @return Actual width of shelf, accounting for possible ongoing width animation
*/
public int getActualWidth() {
@@ -411,7 +401,8 @@
|| !mShowNotificationShelf
|| numViewsInShelf < 1f;
- final float fractionToShade = Interpolators.STANDARD.getInterpolation(mFractionToShade);
+ final float fractionToShade = Interpolators.STANDARD.getInterpolation(
+ mAmbientState.getFractionToShade());
final float shortestWidth = mShelfIcons.calculateWidthFor(numViewsInShelf);
updateActualWidth(fractionToShade, shortestWidth);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 0fb6ea6..039a362 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -573,11 +573,10 @@
} catch (RuntimeException e) {
Log.e(TAG, "Unable to recover builder", e);
// Trying to get the app name from the app info instead.
- Parcelable appInfo = n.extras.getParcelable(
- Notification.EXTRA_BUILDER_APPLICATION_INFO);
- if (appInfo instanceof ApplicationInfo) {
- appName = String.valueOf(((ApplicationInfo) appInfo).loadLabel(
- c.getPackageManager()));
+ ApplicationInfo appInfo = n.extras.getParcelable(
+ Notification.EXTRA_BUILDER_APPLICATION_INFO, ApplicationInfo.class);
+ if (appInfo != null) {
+ appName = String.valueOf(appInfo.loadLabel(c.getPackageManager()));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index 0fd9272..4fc347a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -542,7 +542,8 @@
if (senderPerson == null) {
return true;
}
- Person user = extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON);
+ Person user = extras.getParcelable(
+ Notification.EXTRA_MESSAGING_PERSON, Person.class);
return Objects.equals(user, senderPerson);
}
}
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 efb46b96..7245cb2 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
@@ -2658,9 +2658,6 @@
return;
}
- // bail out if no public version
- if (mPublicLayout.getChildCount() == 0) return;
-
if (!animated) {
mPublicLayout.animate().cancel();
mPrivateLayout.animate().cancel();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapper.java
index 79f99b8..8732696 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapper.java
@@ -44,9 +44,8 @@
private void updateImageTag(StatusBarNotification sbn) {
final Bundle extras = sbn.getNotification().extras;
- boolean bigLargeIconSet = extras.containsKey(Notification.EXTRA_LARGE_ICON_BIG);
- if (bigLargeIconSet) {
- Icon bigLargeIcon = extras.getParcelable(Notification.EXTRA_LARGE_ICON_BIG);
+ Icon bigLargeIcon = extras.getParcelable(Notification.EXTRA_LARGE_ICON_BIG, Icon.class);
+ if (bigLargeIcon != null) {
mRightIcon.setTag(ImageTransformState.ICON_TAG, bigLargeIcon);
mLeftIcon.setTag(ImageTransformState.ICON_TAG, bigLargeIcon);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index 2f1022a..9acd60e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -31,6 +31,7 @@
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.BypassController;
import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.SectionProvider;
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import javax.inject.Inject;
@@ -45,6 +46,10 @@
private final SectionProvider mSectionProvider;
private final BypassController mBypassController;
+ /**
+ * Used to read bouncer states.
+ */
+ private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private int mScrollY;
private boolean mDimmed;
private ActivatableNotificationView mActivatedChild;
@@ -77,6 +82,23 @@
private boolean mAppearing;
private float mPulseHeight = MAX_PULSE_HEIGHT;
+ /** Fraction of lockscreen to shade animation (on lockscreen swipe down). */
+ private float mFractionToShade;
+
+ /**
+ * @param fractionToShade Fraction of lockscreen to shade transition
+ */
+ public void setFractionToShade(float fractionToShade) {
+ mFractionToShade = fractionToShade;
+ }
+
+ /**
+ * @return fractionToShade Fraction of lockscreen to shade transition
+ */
+ public float getFractionToShade() {
+ return mFractionToShade;
+ }
+
/** How we much we are sleeping. 1f fully dozing (AOD), 0f fully awake (for all other states) */
private float mDozeAmount = 0.0f;
@@ -204,9 +226,11 @@
public AmbientState(
Context context,
@NonNull SectionProvider sectionProvider,
- @NonNull BypassController bypassController) {
+ @NonNull BypassController bypassController,
+ @Nullable StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
mSectionProvider = sectionProvider;
mBypassController = bypassController;
+ mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
reload(context);
}
@@ -661,4 +685,14 @@
public int getStackTopMargin() {
return mStackTopMargin;
}
+
+ /**
+ * Check to see if we are about to show bouncer.
+ *
+ * @return if bouncer expansion is between 0 and 1.
+ */
+ public boolean isBouncerInTransit() {
+ return mStatusBarKeyguardViewManager != null
+ && mStatusBarKeyguardViewManager.isBouncerInTransit();
+ }
}
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 b52fd61..851794c 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
@@ -2295,7 +2295,7 @@
int visibleIndex
) {
return mStackScrollAlgorithm.getGapHeightForChild(mSectionsManager, visibleIndex, current,
- previous);
+ previous, mAmbientState.getFractionToShade(), mAmbientState.isOnKeyguard());
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
@@ -5501,7 +5501,7 @@
* where it remains until the next lockscreen-to-shade transition.
*/
public void setFractionToShade(float fraction) {
- mShelf.setFractionToShade(fraction);
+ mAmbientState.setFractionToShade(fraction);
requestChildrenUpdate();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
index 9417aac..2b11f69 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
@@ -19,9 +19,11 @@
import android.content.res.Resources
import android.util.Log
import android.view.View.GONE
+import androidx.annotation.VisibleForTesting
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.statusbar.LockscreenShadeTransitionController
import com.android.systemui.statusbar.StatusBarState.KEYGUARD
import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
@@ -41,6 +43,7 @@
@Inject
constructor(
private val statusBarStateController: SysuiStatusBarStateController,
+ private val lockscreenShadeTransitionController: LockscreenShadeTransitionController,
@Main private val resources: Resources
) {
@@ -129,7 +132,7 @@
yield(dividerHeight + shelfIntrinsicHeight) // Only shelf.
children.forEachIndexed { i, currentNotification ->
- height += currentNotification.spaceNeeded(i, previous, stack, onLockscreen)
+ height += spaceNeeded(currentNotification, i, previous, stack, onLockscreen)
previous = currentNotification
val shelfHeight =
@@ -156,22 +159,28 @@
private val NotificationStackScrollLayout.childrenSequence: Sequence<ExpandableView>
get() = children.map { it as ExpandableView }
- private fun onLockscreen() = statusBarStateController.state == KEYGUARD
+ @VisibleForTesting
+ fun onLockscreen() : Boolean {
+ return statusBarStateController.state == KEYGUARD
+ && lockscreenShadeTransitionController.fractionToShade == 0f
+ }
- private fun ExpandableView.spaceNeeded(
+ @VisibleForTesting
+ fun spaceNeeded(
+ view: ExpandableView,
visibleIndex: Int,
previousView: ExpandableView?,
stack: NotificationStackScrollLayout,
onLockscreen: Boolean
): Float {
- assert(isShowable(onLockscreen))
+ assert(view.isShowable(onLockscreen))
var size =
if (onLockscreen) {
- getMinHeight(/* ignoreTemporaryStates= */ true).toFloat()
+ view.getMinHeight(/* ignoreTemporaryStates= */ true).toFloat()
} else {
- intrinsicHeight.toFloat()
+ view.intrinsicHeight.toFloat()
}
- size += calculateGapAndDividerHeight(stack, previousView, current = this, visibleIndex)
+ size += calculateGapAndDividerHeight(stack, previousView, current = view, visibleIndex)
return size
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index c097133..22242b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -27,6 +27,7 @@
import androidx.annotation.VisibleForTesting;
import com.android.internal.policy.SystemBarUtils;
+import com.android.keyguard.BouncerPanelExpansionCalculator;
import com.android.systemui.R;
import com.android.systemui.animation.ShadeInterpolation;
import com.android.systemui.statusbar.EmptyShadeView;
@@ -53,6 +54,7 @@
private int mPaddingBetweenElements;
private int mGapHeight;
+ private int mGapHeightOnLockscreen;
private int mCollapsedSize;
private StackScrollAlgorithmState mTempAlgorithmState = new StackScrollAlgorithmState();
@@ -86,6 +88,8 @@
mPinnedZTranslationExtra = res.getDimensionPixelSize(
R.dimen.heads_up_pinned_elevation);
mGapHeight = res.getDimensionPixelSize(R.dimen.notification_section_divider_height);
+ mGapHeightOnLockscreen = res.getDimensionPixelSize(
+ R.dimen.notification_section_divider_height_lockscreen);
mNotificationScrimPadding = res.getDimensionPixelSize(R.dimen.notification_side_paddings);
mMarginBottom = res.getDimensionPixelSize(R.dimen.notification_panel_margin_bottom);
}
@@ -304,7 +308,8 @@
ambientState.getSectionProvider(), i,
view, getPreviousView(i, state));
if (applyGapHeight) {
- currentY += mGapHeight;
+ currentY += getGapForLocation(
+ ambientState.getFractionToShade(), ambientState.isOnKeyguard());
}
if (ambientState.getShelf() != null) {
@@ -431,7 +436,9 @@
} else if (ambientState.isExpansionChanging()) {
// Adjust alpha for shade open & close.
float expansion = ambientState.getExpansionFraction();
- viewState.alpha = ShadeInterpolation.getContentAlpha(expansion);
+ viewState.alpha = ambientState.isBouncerInTransit()
+ ? BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(expansion)
+ : ShadeInterpolation.getContentAlpha(expansion);
}
if (ambientState.isShadeExpanded() && view.mustStayOnScreen()
@@ -451,8 +458,10 @@
ambientState.getSectionProvider(), i,
view, getPreviousView(i, algorithmState));
if (applyGapHeight) {
- algorithmState.mCurrentYPosition += expansionFraction * mGapHeight;
- algorithmState.mCurrentExpandedYPosition += mGapHeight;
+ final float gap = getGapForLocation(
+ ambientState.getFractionToShade(), ambientState.isOnKeyguard());
+ algorithmState.mCurrentYPosition += expansionFraction * gap;
+ algorithmState.mCurrentExpandedYPosition += gap;
}
viewState.yTranslation = algorithmState.mCurrentYPosition;
@@ -536,16 +545,29 @@
SectionProvider sectionProvider,
int visibleIndex,
View child,
- View previousChild) {
+ View previousChild,
+ float fractionToShade,
+ boolean onKeyguard) {
if (childNeedsGapHeight(sectionProvider, visibleIndex, child,
previousChild)) {
- return mGapHeight;
+ return getGapForLocation(fractionToShade, onKeyguard);
} else {
return 0;
}
}
+ @VisibleForTesting
+ float getGapForLocation(float fractionToShade, boolean onKeyguard) {
+ if (fractionToShade > 0f) {
+ return MathUtils.lerp(mGapHeightOnLockscreen, mGapHeight, fractionToShade);
+ }
+ if (onKeyguard) {
+ return mGapHeightOnLockscreen;
+ }
+ return mGapHeight;
+ }
+
/**
* Does a given child need a gap, i.e spacing before a view?
*
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 111cbbe..3ccef9d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
@@ -23,12 +23,14 @@
import android.view.IWindowManager;
import android.view.MotionEvent;
+import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.AutoHideUiElement;
import javax.inject.Inject;
/** A controller to control all auto-hide things. Also see {@link AutoHideUiElement}. */
+@SysUISingleton
public class AutoHideController {
private static final String TAG = "AutoHideController";
private static final long AUTO_HIDE_TIMEOUT_MS = 2250;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
index 96fa8a5..34cd1ce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
@@ -20,11 +20,14 @@
import android.graphics.Rect
import android.os.LocaleList
import android.view.View.LAYOUT_DIRECTION_RTL
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.policy.ConfigurationController
import java.util.ArrayList
+import javax.inject.Inject
-class ConfigurationControllerImpl(context: Context) : ConfigurationController {
+@SysUISingleton
+class ConfigurationControllerImpl @Inject constructor(context: Context) : ConfigurationController {
private val listeners: MutableList<ConfigurationController.ConfigurationListener> = ArrayList()
private val lastConfig = Configuration()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
index 7db677a..3e32b64 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
@@ -71,7 +71,13 @@
isListening = false
updateListeningState()
keyguardUpdateMonitor.requestFaceAuth(true)
- keyguardUpdateMonitor.requestActiveUnlock()
+ if (keyguardUpdateMonitor.mRequestActiveUnlockOnWakeup) {
+ keyguardUpdateMonitor.requestActiveUnlock("wake-unlock," +
+ " extra=KeyguardLiftController")
+ } else if (keyguardUpdateMonitor.mInitiateActiveUnlockOnWakeup) {
+ keyguardUpdateMonitor.initiateActiveUnlock("wake-initiate," +
+ " extra=KeyguardLiftController")
+ }
}
}
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 c1142ed..af62f18 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -3210,7 +3210,7 @@
@Override
protected void startUnlockHintAnimation() {
- if (mPowerManager.isPowerSaveMode()) {
+ if (mPowerManager.isPowerSaveMode() || mAmbientState.getDozeAmount() > 0f) {
onUnlockHintStarted();
onUnlockHintFinished();
return;
@@ -3336,6 +3336,12 @@
.log(LockscreenUiEvent.LOCKSCREEN_LOCK_SHOW_HINT);
startUnlockHintAnimation();
}
+ if (mUpdateMonitor.isFaceEnrolled()
+ && mUpdateMonitor.mRequestActiveUnlockOnUnlockIntent
+ && mKeyguardBypassController.canBypass()) {
+ mUpdateMonitor.requestActiveUnlock("unlock-intent,"
+ + " extra=lockScreenEmptySpaceTap", true);
+ }
}
return true;
case StatusBarState.SHADE_LOCKED:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
index 56c74bf..24660b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
@@ -288,7 +288,7 @@
final boolean keyguardOrAod = state.mKeyguardShowing
|| (state.mDozing && mDozeParameters.getAlwaysOn());
if ((keyguardOrAod && !state.mBackdropShowing && !state.mLightRevealScrimOpaque)
- || mKeyguardViewMediator.isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe()) {
+ || mKeyguardViewMediator.isAnimatingBetweenKeyguardAndSurfaceBehind()) {
// Show the wallpaper if we're on keyguard/AOD and the wallpaper is not occluded by a
// solid backdrop. Also, show it if we are currently animating between the
// keyguard and the surface behind the keyguard - we want to use the wallpaper as a
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index d492c57..4ba8441 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -48,7 +48,6 @@
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.LatencyTracker;
-import com.android.keyguard.BouncerPanelExpansionCalculator;
import com.android.systemui.DejankUtils;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
@@ -796,9 +795,7 @@
}
mExpandedFraction = Math.min(1f,
maxPanelHeight == 0 ? 0 : mExpandedHeight / maxPanelHeight);
- mAmbientState.setExpansionFraction(mStatusBarKeyguardViewManager.bouncerIsInTransit()
- ? BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(mExpandedFraction)
- : mExpandedFraction);
+ mAmbientState.setExpansionFraction(mExpandedFraction);
onHeightUpdated(mExpandedHeight);
updatePanelExpansionAndVisibility();
});
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index cc2ff3f..8c1ed19 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -1074,7 +1074,7 @@
}
private float getInterpolatedFraction() {
- if (mStatusBarKeyguardViewManager.bouncerIsInTransit()) {
+ if (mStatusBarKeyguardViewManager.isBouncerInTransit()) {
return BouncerPanelExpansionCalculator
.aboutToShowBouncerProgress(mPanelExpansionFraction);
}
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 6414487..6758b76 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -589,10 +589,12 @@
}
private void updateAlternateAuthShowing(boolean updateScrim) {
+ final boolean isShowingAltAuth = isShowingAlternateAuth();
if (mKeyguardMessageAreaController != null) {
- mKeyguardMessageAreaController.setAltBouncerShowing(isShowingAlternateAuth());
+ mKeyguardMessageAreaController.setAltBouncerShowing(isShowingAltAuth);
}
- mBypassController.setAltBouncerShowing(isShowingAlternateAuth());
+ mBypassController.setAltBouncerShowing(isShowingAltAuth);
+ mKeyguardUpdateManager.setUdfpsBouncerShowing(isShowingAltAuth);
if (updateScrim) {
mCentralSurfaces.updateScrimController();
@@ -1268,6 +1270,8 @@
pw.println(" mAfterKeyguardGoneAction: " + mAfterKeyguardGoneAction);
pw.println(" mAfterKeyguardGoneRunnables: " + mAfterKeyguardGoneRunnables);
pw.println(" mPendingWakeupAction: " + mPendingWakeupAction);
+ pw.println(" isBouncerShowing(): " + isBouncerShowing());
+ pw.println(" bouncerIsOrWillBeShowing(): " + bouncerIsOrWillBeShowing());
if (mBouncer != null) {
mBouncer.dump(pw);
@@ -1376,7 +1380,7 @@
/**
* Returns if bouncer expansion is between 0 and 1 non-inclusive.
*/
- public boolean bouncerIsInTransit() {
+ public boolean isBouncerInTransit() {
if (mBouncer == null) return false;
return mBouncer.inTransit();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
index c326835..1b73539 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/StatusBarPolicyModule.java
@@ -29,10 +29,13 @@
import com.android.systemui.statusbar.connectivity.AccessPointControllerImpl;
import com.android.systemui.statusbar.connectivity.NetworkController;
import com.android.systemui.statusbar.connectivity.NetworkControllerImpl;
+import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.CastControllerImpl;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.DeviceControlsController;
import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl;
import com.android.systemui.statusbar.policy.DevicePostureController;
@@ -85,6 +88,10 @@
/** */
@Binds
+ ConfigurationController bindConfigurationController(ConfigurationControllerImpl impl);
+
+ /** */
+ @Binds
ExtensionController provideExtensionController(ExtensionControllerImpl controllerImpl);
/** */
@@ -182,4 +189,11 @@
return resources.getStringArray(
R.array.config_perDeviceStateRotationLockDefaults);
}
+
+ /** */
+ @Provides
+ @SysUISingleton
+ static DataSaverController provideDataSaverController(NetworkController networkController) {
+ return networkController.getDataSaverController();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeModule.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeModule.java
new file mode 100644
index 0000000..7fa90df
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeModule.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 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.theme;
+
+import android.content.res.Resources;
+
+import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.util.concurrency.SysUIConcurrencyModule;
+
+import javax.inject.Named;
+
+import dagger.Module;
+import dagger.Provides;
+
+/** */
+@Module(includes = {SysUIConcurrencyModule.class})
+public class ThemeModule {
+ static final String LAUNCHER_PACKAGE = "theme_launcher_package";
+ static final String THEME_PICKER_PACKAGE = "theme_picker_package";
+
+ /** */
+ @Provides
+ @Named(LAUNCHER_PACKAGE)
+ static String provideLauncherPackage(@Main Resources resources) {
+ return resources.getString(R.string.launcher_overlayable_package);
+ }
+
+ /** */
+ @Provides
+ @Named(THEME_PICKER_PACKAGE)
+ static String provideThemePickerPackage(@Main Resources resources) {
+ return resources.getString(R.string.themepicker_overlayable_package);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
index d795d81..ba39367 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
@@ -31,6 +31,7 @@
import com.android.systemui.Dumpable;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dump.DumpManager;
import com.google.android.collect.Lists;
@@ -45,6 +46,9 @@
import java.util.concurrent.Executor;
import java.util.stream.Collectors;
+import javax.inject.Inject;
+import javax.inject.Named;
+
/**
* Responsible for orchestrating overlays, based on user preferences and other inputs from
* {@link ThemeOverlayController}.
@@ -134,17 +138,17 @@
private final Map<String, String> mCategoryToTargetPackage = new ArrayMap<>();
private final OverlayManager mOverlayManager;
private final Executor mBgExecutor;
- private final Executor mMainExecutor;
private final String mLauncherPackage;
private final String mThemePickerPackage;
+ @Inject
public ThemeOverlayApplier(OverlayManager overlayManager,
- Executor bgExecutor,
- Executor mainExecutor,
- String launcherPackage, String themePickerPackage, DumpManager dumpManager) {
+ @Background Executor bgExecutor,
+ @Named(ThemeModule.LAUNCHER_PACKAGE) String launcherPackage,
+ @Named(ThemeModule.THEME_PICKER_PACKAGE) String themePickerPackage,
+ DumpManager dumpManager) {
mOverlayManager = overlayManager;
mBgExecutor = bgExecutor;
- mMainExecutor = mainExecutor;
mLauncherPackage = launcherPackage;
mThemePickerPackage = themePickerPackage;
mTargetPackageToCategories.put(ANDROID_PACKAGE, Sets.newHashSet(
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java b/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java
index 6fdce1a..640adcc 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSysUIComponent.java
@@ -22,6 +22,12 @@
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.SystemUIBinder;
import com.android.systemui.dagger.SystemUIModule;
+import com.android.systemui.statusbar.dagger.CentralSurfacesDependenciesModule;
+import com.android.systemui.statusbar.notification.dagger.NotificationsModule;
+import com.android.systemui.statusbar.notification.row.NotificationRowModule;
+
+import com.android.systemui.keyguard.dagger.KeyguardModule;
+import com.android.systemui.recents.RecentsModule;
import dagger.Subcomponent;
@@ -30,13 +36,17 @@
*/
@SysUISingleton
@Subcomponent(modules = {
+ CentralSurfacesDependenciesModule.class,
DefaultComponentBinder.class,
DependencyProvider.class,
- SystemUIBinder.class,
+ KeyguardModule.class,
+ NotificationRowModule.class,
+ NotificationsModule.class,
+ RecentsModule.class,
SystemUIModule.class,
+ TvSystemUIBinder.class,
TVSystemUICoreStartableModule.class,
- TvSystemUIModule.class,
- TvSystemUIBinder.class})
+ TvSystemUIModule.class})
public interface TvSysUIComponent extends SysUIComponent {
/**
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbAudioWarningDialogMessage.java b/packages/SystemUI/src/com/android/systemui/usb/UsbAudioWarningDialogMessage.java
new file mode 100644
index 0000000..e06353b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbAudioWarningDialogMessage.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2022 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.usb;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
+import android.content.res.Resources;
+import android.util.Log;
+
+import com.android.systemui.R;
+
+import java.lang.annotation.Retention;
+
+import javax.inject.Inject;
+
+/**
+ * USB Audio devices warning dialog messages help class.
+ */
+public class UsbAudioWarningDialogMessage {
+ private static final String TAG = "UsbAudioWarningDialogMessage";
+
+ @Retention(SOURCE)
+ @IntDef({TYPE_PERMISSION, TYPE_CONFIRM})
+ public @interface DialogType {}
+ public static final int TYPE_PERMISSION = 0;
+ public static final int TYPE_CONFIRM = 1;
+
+ private int mDialogType;
+ private UsbDialogHelper mDialogHelper;
+
+ @Inject
+ public UsbAudioWarningDialogMessage() {
+ }
+
+ /**
+ * Initialize USB audio warning dialog message type and helper class.
+ * @param type Dialog type for Activity.
+ * @param usbDialogHelper Helper class for getting USB permission and confirm dialogs
+ */
+ public void init(@DialogType int type, UsbDialogHelper usbDialogHelper) {
+ mDialogType = type;
+ mDialogHelper = usbDialogHelper;
+ }
+
+ boolean hasRecordPermission() {
+ return mDialogHelper.packageHasAudioRecordingPermission();
+ }
+
+ boolean isUsbAudioDevice() {
+ return mDialogHelper.isUsbDevice() && (mDialogHelper.deviceHasAudioCapture()
+ || (mDialogHelper.deviceHasAudioPlayback()));
+ }
+
+ boolean hasAudioPlayback() {
+ return mDialogHelper.deviceHasAudioPlayback();
+ }
+
+ boolean hasAudioCapture() {
+ return mDialogHelper.deviceHasAudioCapture();
+ }
+
+ /**
+ * According to USB audio warning dialog matrix table to return warning message id.
+ * @return string resId for USB audio warning dialog message, otherwise {ID_NULL}.
+ * See usb_audio.md for USB audio Permission and Confirmation warning dialog resource
+ * string id matrix table.
+ */
+ public int getMessageId() {
+ if (!mDialogHelper.isUsbDevice()) {
+ return getUsbAccessoryPromptId();
+ }
+
+ if (hasRecordPermission() && isUsbAudioDevice()) {
+ // case# 1, 2, 3
+ return R.string.usb_audio_device_prompt;
+ } else if (!hasRecordPermission() && isUsbAudioDevice() && hasAudioPlayback()
+ && !hasAudioCapture()) {
+ // case# 5
+ return R.string.usb_audio_device_prompt;
+ }
+
+ if (!hasRecordPermission() && isUsbAudioDevice() && hasAudioCapture()) {
+ // case# 6,7
+ return R.string.usb_audio_device_prompt_warn;
+ }
+
+ Log.w(TAG, "Only shows title with empty content description!");
+ return Resources.ID_NULL;
+ }
+
+ /**
+ * Gets prompt dialog title.
+ * @return string id for USB prompt dialog title.
+ */
+ public int getPromptTitleId() {
+ return (mDialogType == TYPE_PERMISSION)
+ ? R.string.usb_audio_device_permission_prompt_title
+ : R.string.usb_audio_device_confirm_prompt_title;
+ }
+
+ /**
+ * Gets USB Accessory prompt message id.
+ * @return string id for USB Accessory prompt message.
+ */
+ public int getUsbAccessoryPromptId() {
+ return (mDialogType == TYPE_PERMISSION)
+ ? R.string.usb_accessory_permission_prompt : R.string.usb_accessory_confirm_prompt;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
index f4558fe..6e523d8 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
@@ -16,7 +16,10 @@
package com.android.systemui.usb;
-import com.android.systemui.R;
+import android.content.res.Resources;
+import android.os.Bundle;
+
+import javax.inject.Inject;
/**
* Dialog shown to confirm the package to start when a USB device or accessory is attached and there
@@ -24,23 +27,35 @@
*/
public class UsbConfirmActivity extends UsbDialogActivity {
+ private UsbAudioWarningDialogMessage mUsbConfirmMessageHandler;
+
+ @Inject
+ public UsbConfirmActivity(UsbAudioWarningDialogMessage usbAudioWarningDialogMessage) {
+ mUsbConfirmMessageHandler = usbAudioWarningDialogMessage;
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ mUsbConfirmMessageHandler.init(UsbAudioWarningDialogMessage.TYPE_CONFIRM, mDialogHelper);
+ }
+
@Override
protected void onResume() {
super.onResume();
- final int strId;
- boolean useRecordWarning = false;
- if (mDialogHelper.isUsbDevice()) {
- useRecordWarning = mDialogHelper.deviceHasAudioCapture()
- && !mDialogHelper.packageHasAudioRecordingPermission();
- strId = useRecordWarning
- ? R.string.usb_device_confirm_prompt_warn
- : R.string.usb_device_confirm_prompt;
- } else {
- // UsbAccessory case
- strId = R.string.usb_accessory_confirm_prompt;
- }
- setAlertParams(strId);
// Only show the "always use" checkbox if there is no USB/Record warning
+ final boolean useRecordWarning = mDialogHelper.isUsbDevice()
+ && (mDialogHelper.deviceHasAudioCapture()
+ && !mDialogHelper.packageHasAudioRecordingPermission());
+
+ final int titleId = mUsbConfirmMessageHandler.getPromptTitleId();
+ final String title = getString(titleId, mDialogHelper.getAppName(),
+ mDialogHelper.getDeviceDescription());
+ final int messageId = mUsbConfirmMessageHandler.getMessageId();
+ String message = (messageId != Resources.ID_NULL)
+ ? getString(messageId, mDialogHelper.getAppName(),
+ mDialogHelper.getDeviceDescription()) : null;
+ setAlertParams(title, message);
if (!useRecordWarning) {
addAlwaysUseCheckbox();
}
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbDialogActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDialogActivity.java
index 930bc33..55dec5f 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbDialogActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDialogActivity.java
@@ -41,7 +41,7 @@
private TextView mClearDefaultHint;
@Override
- protected final void onCreate(Bundle savedInstanceState) {
+ protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addSystemFlags(
WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
@@ -87,11 +87,10 @@
}
}
- void setAlertParams(int strId) {
+ void setAlertParams(String title, String message) {
final AlertController.AlertParams ap = mAlertParams;
- ap.mTitle = mDialogHelper.getAppName();
- ap.mMessage = getString(strId, mDialogHelper.getAppName(),
- mDialogHelper.getDeviceDescription());
+ ap.mTitle = title;
+ ap.mMessage = message;
ap.mPositiveButtonText = getString(android.R.string.ok);
ap.mNegativeButtonText = getString(android.R.string.cancel);
ap.mPositiveButtonListener = this;
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbDialogHelper.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDialogHelper.java
index d63fb86..3f061d3 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbDialogHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDialogHelper.java
@@ -134,6 +134,13 @@
}
/**
+ * @return True if the intent contains a UsbDevice which can play audio.
+ */
+ public boolean deviceHasAudioPlayback() {
+ return mDevice != null && mDevice.getHasAudioPlayback();
+ }
+
+ /**
* @return True if the package has RECORD_AUDIO permission specified in its manifest.
*/
public boolean packageHasAudioRecordingPermission() {
@@ -272,15 +279,15 @@
return desc;
}
- /**
- * Whether the calling package can set as default handler of the USB device or accessory.
- * In case of a UsbAccessory this is the case if the calling package has an intent filter for
- * {@link UsbManager#ACTION_USB_ACCESSORY_ATTACHED} with a usb-accessory filter matching the
- * attached accessory. In case of a UsbDevice this is the case if the calling package has an
- * intent filter for {@link UsbManager#ACTION_USB_DEVICE_ATTACHED} with a usb-device filter
- * matching the attached device.
- *
- * @return True if the package can be default for the USB device.
+ /**
+ * Whether the calling package can set as default handler of the USB device or accessory.
+ * In case of a UsbAccessory this is the case if the calling package has an intent filter for
+ * {@link UsbManager#ACTION_USB_ACCESSORY_ATTACHED} with a usb-accessory filter matching the
+ * attached accessory. In case of a UsbDevice this is the case if the calling package has an
+ * intent filter for {@link UsbManager#ACTION_USB_DEVICE_ATTACHED} with a usb-device filter
+ * matching the attached device.
+ *
+ * @return True if the package can be default for the USB device.
*/
public boolean canBeDefault() {
return mCanBeDefault;
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
index 38d6347..9484d3a 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
@@ -16,7 +16,10 @@
package com.android.systemui.usb;
-import com.android.systemui.R;
+import android.content.res.Resources;
+import android.os.Bundle;
+
+import javax.inject.Inject;
/**
* Dialog shown when a package requests access to a USB device or accessory.
@@ -24,23 +27,36 @@
public class UsbPermissionActivity extends UsbDialogActivity {
private boolean mPermissionGranted = false;
+ private UsbAudioWarningDialogMessage mUsbPermissionMessageHandler;
+
+ @Inject
+ public UsbPermissionActivity(UsbAudioWarningDialogMessage usbAudioWarningDialogMessage) {
+ mUsbPermissionMessageHandler = usbAudioWarningDialogMessage;
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ mUsbPermissionMessageHandler.init(UsbAudioWarningDialogMessage.TYPE_PERMISSION,
+ mDialogHelper);
+ }
@Override
protected void onResume() {
super.onResume();
- final int strId;
- boolean useRecordWarning = false;
- if (mDialogHelper.isUsbDevice()) {
- useRecordWarning = mDialogHelper.deviceHasAudioCapture()
- && !mDialogHelper.packageHasAudioRecordingPermission();
- strId = useRecordWarning
- ? R.string.usb_device_permission_prompt_warn
- : R.string.usb_device_permission_prompt;
- } else {
- // UsbAccessory case
- strId = R.string.usb_accessory_permission_prompt;
- }
- setAlertParams(strId);
+ final boolean useRecordWarning = mDialogHelper.isUsbDevice()
+ && (mDialogHelper.deviceHasAudioCapture()
+ && !mDialogHelper.packageHasAudioRecordingPermission());
+
+ final int titleId = mUsbPermissionMessageHandler.getPromptTitleId();
+ final String title = getString(titleId, mDialogHelper.getAppName(),
+ mDialogHelper.getDeviceDescription());
+ final int messageId = mUsbPermissionMessageHandler.getMessageId();
+ String message = (messageId != Resources.ID_NULL)
+ ? getString(messageId, mDialogHelper.getAppName(),
+ mDialogHelper.getDeviceDescription()) : null;
+ setAlertParams(title, message);
+
// Only show the "always use" checkbox if there is no USB/Record warning
if (!useRecordWarning && mDialogHelper.canBeDefault()) {
addAlwaysUseCheckbox();
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/GlobalConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/GlobalConcurrencyModule.java
index 107fe87..323db5c 100644
--- a/packages/SystemUI/src/com/android/systemui/util/concurrency/GlobalConcurrencyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/GlobalConcurrencyModule.java
@@ -64,6 +64,15 @@
}
/**
+ * @deprecated Use @Main Handler.
+ */
+ @Deprecated
+ @Provides
+ public static Handler provideHandler() {
+ return new Handler();
+ }
+
+ /**
* Provide a Main-Thread Executor.
*/
@Provides
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
index 8f61abc..8c736dc 100644
--- a/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
@@ -16,6 +16,8 @@
package com.android.systemui.util.concurrency;
+import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME;
+
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
@@ -28,6 +30,8 @@
import java.util.concurrent.Executor;
+import javax.inject.Named;
+
import dagger.Module;
import dagger.Provides;
@@ -162,4 +166,14 @@
@Background DelayableExecutor executor) {
return new MessageRouterImpl(executor);
}
+
+ /** */
+ @Provides
+ @SysUISingleton
+ @Named(TIME_TICK_HANDLER_NAME)
+ public static Handler provideTimeTickHandler() {
+ HandlerThread thread = new HandlerThread("TimeTick");
+ thread.start();
+ return new Handler(thread.getLooper());
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/LeakDetector.java b/packages/SystemUI/src/com/android/systemui/util/leak/LeakDetector.java
index 95e8273..f0e3890 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/LeakDetector.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/LeakDetector.java
@@ -17,9 +17,9 @@
package com.android.systemui.util.leak;
import android.os.Build;
+import android.util.IndentingPrintWriter;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.IndentingPrintWriter;
import com.android.systemui.Dumpable;
import com.android.systemui.dump.DumpManager;
@@ -133,17 +133,4 @@
pw.decreaseIndent();
pw.println();
}
-
- public static LeakDetector create(DumpManager dumpManager) {
- if (ENABLED) {
- TrackedCollections collections = new TrackedCollections();
- return new LeakDetector(
- collections,
- new TrackedGarbage(collections),
- new TrackedObjects(collections),
- dumpManager);
- } else {
- return new LeakDetector(null, null, null, dumpManager);
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/LeakModule.java b/packages/SystemUI/src/com/android/systemui/util/leak/LeakModule.java
new file mode 100644
index 0000000..8f5b4d6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/LeakModule.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 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.leak;
+
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dump.DumpManager;
+import com.android.systemui.util.Compile;
+
+import dagger.Module;
+import dagger.Provides;
+
+/** */
+@Module
+public class LeakModule {
+ @Provides
+ @SysUISingleton
+ LeakDetector providesLeakDetector(DumpManager dumpManager, TrackedCollections collections) {
+ if (Compile.IS_DEBUG) {
+ return new LeakDetector(
+ collections,
+ new TrackedGarbage(collections),
+ new TrackedObjects(collections),
+ dumpManager);
+ } else {
+ return new LeakDetector(null, null, null, dumpManager);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/TrackedCollections.java b/packages/SystemUI/src/com/android/systemui/util/leak/TrackedCollections.java
index 5577daf..a3e13bd 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/TrackedCollections.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/TrackedCollections.java
@@ -24,6 +24,8 @@
import java.util.Map;
import java.util.function.Predicate;
+import javax.inject.Inject;
+
/**
* Tracks the size of collections.
*/
@@ -34,6 +36,10 @@
private final WeakIdentityHashMap<Collection<?>, CollectionState> mCollections
= new WeakIdentityHashMap<>();
+ @Inject
+ TrackedCollections() {
+ }
+
/**
* @see LeakDetector#trackCollection(Collection, String)
*/
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java
index 9b2702f..1243c47 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java
@@ -215,6 +215,7 @@
logoView.setImageDrawable(mContext.getDrawable(R.drawable.ic_qs_plus));
mEmptyStateView.<TextView>requireViewById(R.id.empty_state_title).setText(label);
mEmptyStateView.setOnClickListener(clickListener);
+ mAppButton.setOnClickListener(clickListener);
}
void showErrorMessage(@Nullable CharSequence message) {
@@ -256,6 +257,11 @@
}
@VisibleForTesting
+ Button getAppButton() {
+ return mAppButton;
+ }
+
+ @VisibleForTesting
TextView getErrorView() {
return mErrorView;
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt
index cc606de..b1e2012 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt
@@ -97,5 +97,6 @@
primaryUser = false,
scanningAllowedByStrongAuth = false,
secureCameraLaunched = false,
- switchingUser = false
+ switchingUser = false,
+ udfpsBouncerShowing = false
)
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
index 4da2dc3..d49f4d8 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
@@ -298,7 +298,9 @@
@Test
public void testTwoOrMoreUsersDoesAllowDropDown() {
// GIVEN one user has been setup
- when(mUserSwitcherController.getUsers()).thenReturn(buildUserRecords(2));
+ ArrayList<UserRecord> records = buildUserRecords(2);
+ when(mUserSwitcherController.getCurrentUserRecord()).thenReturn(records.get(0));
+ when(mUserSwitcherController.getUsers()).thenReturn(records);
// WHEN UserSwitcherViewMode is initialized
setupUserSwitcher();
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 775addd..86a4f5a 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -269,7 +269,7 @@
mKeyguardUpdateMonitor.registerCallback(mTestCallback);
mTestableLooper.processAllMessages();
- when(mAuthController.areAllAuthenticatorsRegistered()).thenReturn(true);
+ when(mAuthController.areAllFingerprintAuthenticatorsRegistered()).thenReturn(true);
}
@After
@@ -499,7 +499,7 @@
@Test
public void test_doesNotTryToAuthenticateFingerprint_whenAuthenticatorsNotRegistered() {
- when(mAuthController.areAllAuthenticatorsRegistered()).thenReturn(false);
+ when(mAuthController.areAllFingerprintAuthenticatorsRegistered()).thenReturn(false);
mKeyguardUpdateMonitor.dispatchStartedGoingToSleep(0 /* why */);
mTestableLooper.processAllMessages();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index 4858ab5..28da2f1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -50,6 +50,7 @@
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricPrompt;
+import android.hardware.biometrics.BiometricStateListener;
import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.biometrics.IBiometricContextListener;
import android.hardware.biometrics.IBiometricSysuiReceiver;
@@ -60,7 +61,6 @@
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
-import android.hardware.fingerprint.FingerprintStateListener;
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
import android.os.Bundle;
import android.os.Handler;
@@ -151,7 +151,7 @@
@Captor
ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback> mAuthenticatorsRegisteredCaptor;
@Captor
- ArgumentCaptor<FingerprintStateListener> mFingerprintStateCaptor;
+ ArgumentCaptor<BiometricStateListener> mBiometricStateCaptor;
@Captor
ArgumentCaptor<StatusBarStateController.StateListener> mStatusBarStateListenerCaptor;
@@ -226,7 +226,7 @@
// Callback tests
@Test
- public void testRegistersFingerprintStateListener_afterAllAuthenticatorsAreRegistered()
+ public void testRegistersBiometricStateListener_afterAllAuthenticatorsAreRegistered()
throws RemoteException {
// This test is sensitive to prior FingerprintManager interactions.
reset(mFingerprintManager);
@@ -242,12 +242,12 @@
mAuthenticatorsRegisteredCaptor.capture());
mTestableLooper.processAllMessages();
- verify(mFingerprintManager, never()).registerFingerprintStateListener(any());
+ verify(mFingerprintManager, never()).registerBiometricStateListener(any());
mAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(new ArrayList<>());
mTestableLooper.processAllMessages();
- verify(mFingerprintManager).registerFingerprintStateListener(any());
+ verify(mFingerprintManager).registerBiometricStateListener(any());
}
@Test
@@ -269,11 +269,11 @@
mAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(new ArrayList<>());
mTestableLooper.processAllMessages();
- verify(mFingerprintManager).registerFingerprintStateListener(
- mFingerprintStateCaptor.capture());
+ verify(mFingerprintManager).registerBiometricStateListener(
+ mBiometricStateCaptor.capture());
// Enrollments changed for an unknown sensor.
- mFingerprintStateCaptor.getValue().onEnrollmentsChanged(0 /* userId */,
+ mBiometricStateCaptor.getValue().onEnrollmentsChanged(0 /* userId */,
0xbeef /* sensorId */, true /* hasEnrollments */);
mTestableLooper.processAllMessages();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 05cf6a50..5d624cd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -22,6 +22,7 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.inOrder;
@@ -183,6 +184,8 @@
private SystemUIDialogManager mSystemUIDialogManager;
@Mock
private ActivityLaunchAnimator mActivityLaunchAnimator;
+ @Mock
+ private AlternateUdfpsTouchProvider mTouchProvider;
// Capture listeners so that they can be used to send events
@Captor private ArgumentCaptor<IUdfpsOverlayController> mOverlayCaptor;
@@ -256,7 +259,8 @@
mUnlockedScreenOffAnimationController,
mSystemUIDialogManager,
mLatencyTracker,
- mActivityLaunchAnimator);
+ mActivityLaunchAnimator,
+ Optional.of(mTouchProvider));
verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
mOverlayController = mOverlayCaptor.getValue();
verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
@@ -418,9 +422,10 @@
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
moveEvent.recycle();
// THEN FingerprintManager is notified about onPointerDown
- verify(mFingerprintManager).onPointerDown(eq(TEST_REQUEST_ID),
- eq(mUdfpsController.mSensorProps.sensorId),
+ verify(mTouchProvider).onPointerDown(eq(TEST_REQUEST_ID),
eq(0), eq(0), eq(0f), eq(0f));
+ verify(mFingerprintManager, never()).onPointerDown(anyLong(), anyInt(), anyInt(), anyInt(),
+ anyFloat(), anyFloat());
verify(mLatencyTracker).onActionStart(eq(LatencyTracker.ACTION_UDFPS_ILLUMINATE));
// AND illumination begins
verify(mUdfpsView).startIllumination(mOnIlluminatedRunnableCaptor.capture());
@@ -447,9 +452,10 @@
// AND onIlluminatedRunnable that notifies FingerprintManager is set
verify(mUdfpsView).startIllumination(mOnIlluminatedRunnableCaptor.capture());
mOnIlluminatedRunnableCaptor.getValue().run();
- verify(mFingerprintManager).onPointerDown(eq(TEST_REQUEST_ID),
- eq(mUdfpsController.mSensorProps.sensorId),
+ verify(mTouchProvider).onPointerDown(eq(TEST_REQUEST_ID),
eq(0), eq(0), eq(3f) /* minor */, eq(2f) /* major */);
+ verify(mFingerprintManager, never()).onPointerDown(anyLong(), anyInt(), anyInt(), anyInt(),
+ anyFloat(), anyFloat());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
index 186f2bb..1296417 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
@@ -205,6 +205,7 @@
captureAltAuthInterceptor();
when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true);
+ when(mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()).thenReturn(true);
mAltAuthInterceptor.onBouncerVisibilityChanged();
assertTrue(mController.shouldPauseAuth());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt
index 141b3b44..53dcc8d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt
@@ -37,7 +37,8 @@
dumpManager: DumpManager,
logger: BroadcastDispatcherLogger,
userTracker: UserTracker
-) : BroadcastDispatcher(context, looper, executor, dumpManager, logger, userTracker) {
+) : BroadcastDispatcher(
+ context, looper, executor, dumpManager, logger, userTracker, PendingRemovalStore(logger)) {
private val registeredReceivers = ArraySet<BroadcastReceiver>()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
index 4915ded..3c28d48 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
@@ -16,10 +16,14 @@
package com.android.systemui.dreams;
+import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
+import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -32,6 +36,7 @@
import android.net.NetworkRequest;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
+import android.view.View;
import androidx.test.filters.SmallTest;
@@ -40,6 +45,8 @@
import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
import com.android.systemui.statusbar.policy.NextAlarmController;
import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.statusbar.window.StatusBarWindowStateController;
+import com.android.systemui.statusbar.window.StatusBarWindowStateListener;
import com.android.systemui.touch.TouchInsetManager;
import com.android.systemui.util.time.DateFormatUtil;
@@ -84,6 +91,8 @@
ZenModeController mZenModeController;
@Mock
DreamOverlayNotificationCountProvider mDreamOverlayNotificationCountProvider;
+ @Mock
+ StatusBarWindowStateController mStatusBarWindowStateController;
private final Executor mMainExecutor = Runnable::run;
@@ -107,7 +116,8 @@
mDateFormatUtil,
mSensorPrivacyController,
mDreamOverlayNotificationCountProvider,
- mZenModeController);
+ mZenModeController,
+ mStatusBarWindowStateController);
}
@Test
@@ -401,4 +411,41 @@
verify(mView).showIcon(
DreamOverlayStatusBarView.STATUS_ICON_PRIORITY_MODE_ON, false, null);
}
+
+ @Test
+ public void testStatusBarHiddenWhenSystemStatusBarShown() {
+ mController.onViewAttached();
+
+ final ArgumentCaptor<StatusBarWindowStateListener>
+ callbackCapture = ArgumentCaptor.forClass(StatusBarWindowStateListener.class);
+ verify(mStatusBarWindowStateController).addListener(callbackCapture.capture());
+ callbackCapture.getValue().onStatusBarWindowStateChanged(WINDOW_STATE_SHOWING);
+
+ verify(mView).setVisibility(View.INVISIBLE);
+ }
+
+ @Test
+ public void testStatusBarShownWhenSystemStatusBarHidden() {
+ mController.onViewAttached();
+
+ final ArgumentCaptor<StatusBarWindowStateListener>
+ callbackCapture = ArgumentCaptor.forClass(StatusBarWindowStateListener.class);
+ verify(mStatusBarWindowStateController).addListener(callbackCapture.capture());
+ callbackCapture.getValue().onStatusBarWindowStateChanged(WINDOW_STATE_HIDDEN);
+
+ verify(mView).setVisibility(View.VISIBLE);
+ }
+
+ @Test
+ public void testUnattachedStatusBarVisibilityUnchangedWhenSystemStatusBarHidden() {
+ mController.onViewAttached();
+ mController.onViewDetached();
+
+ final ArgumentCaptor<StatusBarWindowStateListener>
+ callbackCapture = ArgumentCaptor.forClass(StatusBarWindowStateListener.class);
+ verify(mStatusBarWindowStateController).addListener(callbackCapture.capture());
+ callbackCapture.getValue().onStatusBarWindowStateChanged(WINDOW_STATE_SHOWING);
+
+ verify(mView, never()).setVisibility(anyInt());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
index e175af7..d0b3d6d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java
@@ -57,6 +57,8 @@
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import java.util.Optional;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class BouncerSwipeTouchHandlerTest extends SysuiTestCase {
@@ -110,7 +112,7 @@
mTouchHandler = new BouncerSwipeTouchHandler(
mDisplayMetrics,
mStatusBarKeyguardViewManager,
- mCentralSurfaces,
+ Optional.of(mCentralSurfaces),
mNotificationShadeWindowController,
mValueAnimatorCreator,
mVelocityTrackerFactory,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt
index 6626bbe..b43856a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt
@@ -24,7 +24,11 @@
import com.android.internal.statusbar.IStatusBarService
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.commandline.Command
+import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.nullable
import com.android.systemui.util.mockito.withArgCaptor
@@ -37,10 +41,12 @@
import org.mockito.Mock
import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.anyString
+import org.mockito.Mockito.atLeastOnce
import org.mockito.Mockito.inOrder
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
+import org.mockito.Mockito.verifyZeroInteractions
import org.mockito.MockitoAnnotations
import java.io.PrintWriter
import java.io.Serializable
@@ -56,16 +62,18 @@
class FeatureFlagsDebugTest : SysuiTestCase() {
private lateinit var mFeatureFlagsDebug: FeatureFlagsDebug
- @Mock private lateinit var mFlagManager: FlagManager
- @Mock private lateinit var mMockContext: Context
- @Mock private lateinit var mSecureSettings: SecureSettings
- @Mock private lateinit var mSystemProperties: SystemPropertiesHelper
- @Mock private lateinit var mResources: Resources
- @Mock private lateinit var mDumpManager: DumpManager
- @Mock private lateinit var mBarService: IStatusBarService
- private val mFlagMap = mutableMapOf<Int, Flag<*>>()
- private lateinit var mBroadcastReceiver: BroadcastReceiver
- private lateinit var mClearCacheAction: Consumer<Int>
+ @Mock private lateinit var flagManager: FlagManager
+ @Mock private lateinit var mockContext: Context
+ @Mock private lateinit var secureSettings: SecureSettings
+ @Mock private lateinit var systemProperties: SystemPropertiesHelper
+ @Mock private lateinit var resources: Resources
+ @Mock private lateinit var dumpManager: DumpManager
+ @Mock private lateinit var commandRegistry: CommandRegistry
+ @Mock private lateinit var barService: IStatusBarService
+ @Mock private lateinit var pw: PrintWriter
+ private val flagMap = mutableMapOf<Int, Flag<*>>()
+ private lateinit var broadcastReceiver: BroadcastReceiver
+ private lateinit var clearCacheAction: Consumer<Int>
private val teamfoodableFlagA = BooleanFlag(500, false, true)
private val teamfoodableFlagB = BooleanFlag(501, true, true)
@@ -73,34 +81,35 @@
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- mFlagMap.put(teamfoodableFlagA.id, teamfoodableFlagA)
- mFlagMap.put(teamfoodableFlagB.id, teamfoodableFlagB)
+ flagMap.put(teamfoodableFlagA.id, teamfoodableFlagA)
+ flagMap.put(teamfoodableFlagB.id, teamfoodableFlagB)
mFeatureFlagsDebug = FeatureFlagsDebug(
- mFlagManager,
- mMockContext,
- mSecureSettings,
- mSystemProperties,
- mResources,
- mDumpManager,
- mFlagMap,
- mBarService
+ flagManager,
+ mockContext,
+ secureSettings,
+ systemProperties,
+ resources,
+ dumpManager,
+ flagMap,
+ commandRegistry,
+ barService
)
- verify(mFlagManager).onSettingsChangedAction = any()
- mBroadcastReceiver = withArgCaptor {
- verify(mMockContext).registerReceiver(capture(), any(), nullable(), nullable(),
+ verify(flagManager).onSettingsChangedAction = any()
+ broadcastReceiver = withArgCaptor {
+ verify(mockContext).registerReceiver(capture(), any(), nullable(), nullable(),
any())
}
- mClearCacheAction = withArgCaptor {
- verify(mFlagManager).clearCacheAction = capture()
+ clearCacheAction = withArgCaptor {
+ verify(flagManager).clearCacheAction = capture()
}
- whenever(mFlagManager.idToSettingsKey(any())).thenAnswer { "key-${it.arguments[0]}" }
+ whenever(flagManager.idToSettingsKey(any())).thenAnswer { "key-${it.arguments[0]}" }
}
@Test
fun testReadBooleanFlag() {
// Remember that the TEAMFOOD flag is id#1 and has special behavior.
- whenever(mFlagManager.readFlagValue<Boolean>(eq(3), any())).thenReturn(true)
- whenever(mFlagManager.readFlagValue<Boolean>(eq(4), any())).thenReturn(false)
+ whenever(flagManager.readFlagValue<Boolean>(eq(3), any())).thenReturn(true)
+ whenever(flagManager.readFlagValue<Boolean>(eq(4), any())).thenReturn(false)
assertThat(mFeatureFlagsDebug.isEnabled(BooleanFlag(2, true))).isTrue()
assertThat(mFeatureFlagsDebug.isEnabled(BooleanFlag(3, false))).isTrue()
assertThat(mFeatureFlagsDebug.isEnabled(BooleanFlag(4, true))).isFalse()
@@ -109,7 +118,7 @@
@Test
fun testTeamFoodFlag_False() {
- whenever(mFlagManager.readFlagValue<Boolean>(eq(1), any())).thenReturn(false)
+ whenever(flagManager.readFlagValue<Boolean>(eq(1), any())).thenReturn(false)
assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagA)).isFalse()
assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagB)).isTrue()
@@ -120,7 +129,7 @@
@Test
fun testTeamFoodFlag_True() {
- whenever(mFlagManager.readFlagValue<Boolean>(eq(1), any())).thenReturn(true)
+ whenever(flagManager.readFlagValue<Boolean>(eq(1), any())).thenReturn(true)
assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagA)).isTrue()
assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagB)).isTrue()
@@ -131,11 +140,11 @@
@Test
fun testTeamFoodFlag_Overridden() {
- whenever(mFlagManager.readFlagValue<Boolean>(eq(teamfoodableFlagA.id), any()))
+ whenever(flagManager.readFlagValue<Boolean>(eq(teamfoodableFlagA.id), any()))
.thenReturn(true)
- whenever(mFlagManager.readFlagValue<Boolean>(eq(teamfoodableFlagB.id), any()))
+ whenever(flagManager.readFlagValue<Boolean>(eq(teamfoodableFlagB.id), any()))
.thenReturn(false)
- whenever(mFlagManager.readFlagValue<Boolean>(eq(1), any())).thenReturn(true)
+ whenever(flagManager.readFlagValue<Boolean>(eq(1), any())).thenReturn(true)
assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagA)).isTrue()
assertThat(mFeatureFlagsDebug.isEnabled(teamfoodableFlagB)).isFalse()
@@ -146,14 +155,14 @@
@Test
fun testReadResourceBooleanFlag() {
- whenever(mResources.getBoolean(1001)).thenReturn(false)
- whenever(mResources.getBoolean(1002)).thenReturn(true)
- whenever(mResources.getBoolean(1003)).thenReturn(false)
- whenever(mResources.getBoolean(1004)).thenAnswer { throw NameNotFoundException() }
- whenever(mResources.getBoolean(1005)).thenAnswer { throw NameNotFoundException() }
+ whenever(resources.getBoolean(1001)).thenReturn(false)
+ whenever(resources.getBoolean(1002)).thenReturn(true)
+ whenever(resources.getBoolean(1003)).thenReturn(false)
+ whenever(resources.getBoolean(1004)).thenAnswer { throw NameNotFoundException() }
+ whenever(resources.getBoolean(1005)).thenAnswer { throw NameNotFoundException() }
- whenever(mFlagManager.readFlagValue<Boolean>(eq(3), any())).thenReturn(true)
- whenever(mFlagManager.readFlagValue<Boolean>(eq(5), any())).thenReturn(false)
+ whenever(flagManager.readFlagValue<Boolean>(eq(3), any())).thenReturn(true)
+ whenever(flagManager.readFlagValue<Boolean>(eq(5), any())).thenReturn(false)
assertThat(mFeatureFlagsDebug.isEnabled(ResourceBooleanFlag(1, 1001))).isFalse()
assertThat(mFeatureFlagsDebug.isEnabled(ResourceBooleanFlag(2, 1002))).isTrue()
@@ -171,7 +180,7 @@
@Test
fun testReadSysPropBooleanFlag() {
- whenever(mSystemProperties.getBoolean(anyString(), anyBoolean())).thenAnswer {
+ whenever(systemProperties.getBoolean(anyString(), anyBoolean())).thenAnswer {
if ("b".equals(it.getArgument<String?>(0))) {
return@thenAnswer true
}
@@ -187,8 +196,8 @@
@Test
fun testReadStringFlag() {
- whenever(mFlagManager.readFlagValue<String>(eq(3), any())).thenReturn("foo")
- whenever(mFlagManager.readFlagValue<String>(eq(4), any())).thenReturn("bar")
+ whenever(flagManager.readFlagValue<String>(eq(3), any())).thenReturn("foo")
+ whenever(flagManager.readFlagValue<String>(eq(4), any())).thenReturn("bar")
assertThat(mFeatureFlagsDebug.getString(StringFlag(1, "biz"))).isEqualTo("biz")
assertThat(mFeatureFlagsDebug.getString(StringFlag(2, "baz"))).isEqualTo("baz")
assertThat(mFeatureFlagsDebug.getString(StringFlag(3, "buz"))).isEqualTo("foo")
@@ -197,16 +206,16 @@
@Test
fun testReadResourceStringFlag() {
- whenever(mResources.getString(1001)).thenReturn("")
- whenever(mResources.getString(1002)).thenReturn("resource2")
- whenever(mResources.getString(1003)).thenReturn("resource3")
- whenever(mResources.getString(1004)).thenReturn(null)
- whenever(mResources.getString(1005)).thenAnswer { throw NameNotFoundException() }
- whenever(mResources.getString(1006)).thenAnswer { throw NameNotFoundException() }
+ whenever(resources.getString(1001)).thenReturn("")
+ whenever(resources.getString(1002)).thenReturn("resource2")
+ whenever(resources.getString(1003)).thenReturn("resource3")
+ whenever(resources.getString(1004)).thenReturn(null)
+ whenever(resources.getString(1005)).thenAnswer { throw NameNotFoundException() }
+ whenever(resources.getString(1006)).thenAnswer { throw NameNotFoundException() }
- whenever(mFlagManager.readFlagValue<String>(eq(3), any())).thenReturn("override3")
- whenever(mFlagManager.readFlagValue<String>(eq(4), any())).thenReturn("override4")
- whenever(mFlagManager.readFlagValue<String>(eq(6), any())).thenReturn("override6")
+ whenever(flagManager.readFlagValue<String>(eq(3), any())).thenReturn("override3")
+ whenever(flagManager.readFlagValue<String>(eq(4), any())).thenReturn("override4")
+ whenever(flagManager.readFlagValue<String>(eq(6), any())).thenReturn("override6")
assertThat(mFeatureFlagsDebug.getString(ResourceStringFlag(1, 1001))).isEqualTo("")
assertThat(mFeatureFlagsDebug.getString(ResourceStringFlag(2, 1002))).isEqualTo("resource2")
@@ -232,16 +241,16 @@
addFlag(StringFlag(3, "flag3"))
addFlag(ResourceStringFlag(4, 1004))
- mBroadcastReceiver.onReceive(mMockContext, null)
- mBroadcastReceiver.onReceive(mMockContext, Intent())
- mBroadcastReceiver.onReceive(mMockContext, Intent("invalid action"))
- mBroadcastReceiver.onReceive(mMockContext, Intent(FlagManager.ACTION_SET_FLAG))
+ broadcastReceiver.onReceive(mockContext, null)
+ broadcastReceiver.onReceive(mockContext, Intent())
+ broadcastReceiver.onReceive(mockContext, Intent("invalid action"))
+ broadcastReceiver.onReceive(mockContext, Intent(FlagManager.ACTION_SET_FLAG))
setByBroadcast(0, false) // unknown id does nothing
setByBroadcast(1, "string") // wrong type does nothing
setByBroadcast(2, 123) // wrong type does nothing
setByBroadcast(3, false) // wrong type does nothing
setByBroadcast(4, 123) // wrong type does nothing
- verifyNoMoreInteractions(mFlagManager, mSecureSettings)
+ verifyNoMoreInteractions(flagManager, secureSettings)
}
@Test
@@ -249,15 +258,15 @@
addFlag(BooleanFlag(1, false))
// trying to erase an id not in the map does noting
- mBroadcastReceiver.onReceive(
- mMockContext,
+ broadcastReceiver.onReceive(
+ mockContext,
Intent(FlagManager.ACTION_SET_FLAG).putExtra(FlagManager.EXTRA_ID, 0)
)
- verifyNoMoreInteractions(mFlagManager, mSecureSettings)
+ verifyNoMoreInteractions(flagManager, secureSettings)
// valid id with no value puts empty string in the setting
- mBroadcastReceiver.onReceive(
- mMockContext,
+ broadcastReceiver.onReceive(
+ mockContext,
Intent(FlagManager.ACTION_SET_FLAG).putExtra(FlagManager.EXTRA_ID, 1)
)
verifyPutData(1, "", numReads = 0)
@@ -298,48 +307,102 @@
@Test
fun testSetFlagClearsCache() {
val flag1 = addFlag(StringFlag(1, "flag1"))
- whenever(mFlagManager.readFlagValue<String>(eq(1), any())).thenReturn("original")
+ whenever(flagManager.readFlagValue<String>(eq(1), any())).thenReturn("original")
// gets the flag & cache it
assertThat(mFeatureFlagsDebug.getString(flag1)).isEqualTo("original")
- verify(mFlagManager).readFlagValue(eq(1), eq(StringFlagSerializer))
+ verify(flagManager).readFlagValue(eq(1), eq(StringFlagSerializer))
// hit the cache
assertThat(mFeatureFlagsDebug.getString(flag1)).isEqualTo("original")
- verifyNoMoreInteractions(mFlagManager)
+ verifyNoMoreInteractions(flagManager)
// set the flag
setByBroadcast(1, "new")
verifyPutData(1, "{\"type\":\"string\",\"value\":\"new\"}", numReads = 2)
- whenever(mFlagManager.readFlagValue<String>(eq(1), any())).thenReturn("new")
+ whenever(flagManager.readFlagValue<String>(eq(1), any())).thenReturn("new")
assertThat(mFeatureFlagsDebug.getString(flag1)).isEqualTo("new")
- verify(mFlagManager, times(3)).readFlagValue(eq(1), eq(StringFlagSerializer))
+ verify(flagManager, times(3)).readFlagValue(eq(1), eq(StringFlagSerializer))
+ }
+
+ @Test
+ fun testRegisterCommand() {
+ verify(commandRegistry).registerCommand(anyString(), any())
+ }
+
+ @Test
+ fun testNoOpCommand() {
+ val cmd = captureCommand()
+
+ cmd.execute(pw, ArrayList())
+ verify(pw, atLeastOnce()).println()
+ verify(flagManager).readFlagValue<Boolean>(eq(1), any())
+ verifyZeroInteractions(secureSettings)
+ }
+
+ @Test
+ fun testReadFlagCommand() {
+ addFlag(BooleanFlag(1, false))
+ val cmd = captureCommand()
+ cmd.execute(pw, listOf("1"))
+ verify(flagManager).readFlagValue<Boolean>(eq(1), any())
+ }
+
+ @Test
+ fun testSetFlagCommand() {
+ addFlag(BooleanFlag(1, false))
+ val cmd = captureCommand()
+ cmd.execute(pw, listOf("1", "on"))
+ verifyPutData(1, "{\"type\":\"boolean\",\"value\":true}")
+ }
+
+ @Test
+ fun testToggleFlagCommand() {
+ addFlag(BooleanFlag(1, true))
+ val cmd = captureCommand()
+ cmd.execute(pw, listOf("1", "toggle"))
+ verifyPutData(1, "{\"type\":\"boolean\",\"value\":false}", 2)
+ }
+
+ @Test
+ fun testEraseFlagCommand() {
+ addFlag(BooleanFlag(1, true))
+ val cmd = captureCommand()
+ cmd.execute(pw, listOf("1", "erase"))
+ verify(secureSettings).putStringForUser(eq("key-1"), eq(""), anyInt())
}
private fun verifyPutData(id: Int, data: String, numReads: Int = 1) {
- inOrder(mFlagManager, mSecureSettings).apply {
- verify(mFlagManager, times(numReads)).readFlagValue(eq(id), any<FlagSerializer<*>>())
- verify(mFlagManager).idToSettingsKey(eq(id))
- verify(mSecureSettings).putStringForUser(eq("key-$id"), eq(data), anyInt())
- verify(mFlagManager).dispatchListenersAndMaybeRestart(eq(id), any())
+ inOrder(flagManager, secureSettings).apply {
+ verify(flagManager, times(numReads)).readFlagValue(eq(id), any<FlagSerializer<*>>())
+ verify(flagManager).idToSettingsKey(eq(id))
+ verify(secureSettings).putStringForUser(eq("key-$id"), eq(data), anyInt())
+ verify(flagManager).dispatchListenersAndMaybeRestart(eq(id), any())
}.verifyNoMoreInteractions()
- verifyNoMoreInteractions(mFlagManager, mSecureSettings)
+ verifyNoMoreInteractions(flagManager, secureSettings)
}
private fun setByBroadcast(id: Int, value: Serializable?) {
val intent = Intent(FlagManager.ACTION_SET_FLAG)
intent.putExtra(FlagManager.EXTRA_ID, id)
intent.putExtra(FlagManager.EXTRA_VALUE, value)
- mBroadcastReceiver.onReceive(mMockContext, intent)
+ broadcastReceiver.onReceive(mockContext, intent)
}
private fun <F : Flag<*>> addFlag(flag: F): F {
- val old = mFlagMap.put(flag.id, flag)
+ val old = flagMap.put(flag.id, flag)
check(old == null) { "Flag ${flag.id} already registered" }
return flag
}
+ private fun captureCommand(): Command {
+ val captor = argumentCaptor<Function0<Command>>()
+ verify(commandRegistry).registerCommand(anyString(), capture(captor))
+
+ return captor.value.invoke()
+ }
+
@Test
fun testDump() {
val flag1 = BooleanFlag(1, true)
@@ -350,10 +413,10 @@
val flag6 = ResourceStringFlag(6, 1006)
val flag7 = ResourceStringFlag(7, 1007)
- whenever(mResources.getBoolean(1002)).thenReturn(true)
- whenever(mResources.getString(1006)).thenReturn("resource1006")
- whenever(mResources.getString(1007)).thenReturn("resource1007")
- whenever(mFlagManager.readFlagValue(eq(7), eq(StringFlagSerializer)))
+ whenever(resources.getBoolean(1002)).thenReturn(true)
+ whenever(resources.getString(1006)).thenReturn("resource1006")
+ whenever(resources.getString(1007)).thenReturn("resource1007")
+ whenever(flagManager.readFlagValue(eq(7), eq(StringFlagSerializer)))
.thenReturn("override7")
// WHEN the flags have been accessed
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/ColorSchemeTransitionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/ColorSchemeTransitionTest.kt
index 86527d9..8f967ab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/ColorSchemeTransitionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/ColorSchemeTransitionTest.kt
@@ -38,7 +38,6 @@
private const val DEFAULT_COLOR = Color.RED
private const val TARGET_COLOR = Color.BLUE
-private const val BG_COLOR = Color.GREEN
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -66,8 +65,7 @@
transitionFactory = { default, extractColor, applyColor -> mockTransition }
whenever(extractColor.invoke(colorScheme)).thenReturn(TARGET_COLOR)
- colorSchemeTransition = ColorSchemeTransition(context,
- BG_COLOR, mediaViewHolder, transitionFactory)
+ colorSchemeTransition = ColorSchemeTransition(context, mediaViewHolder, transitionFactory)
colorTransition = object : ColorTransition(DEFAULT_COLOR, extractColor, applyColor) {
override fun buildAnimator(): ValueAnimator {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index 74f1393..33db993 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -90,7 +90,6 @@
import org.mockito.junit.MockitoJUnit
private const val KEY = "TEST_KEY"
-private const val BG_COLOR = Color.RED
private const val PACKAGE = "PKG"
private const val ARTIST = "ARTIST"
private const val TITLE = "TITLE"
@@ -171,8 +170,18 @@
@Mock private lateinit var recommendationViewHolder: RecommendationViewHolder
@Mock private lateinit var smartspaceAction: SmartspaceAction
private lateinit var smartspaceData: SmartspaceMediaData
- @Mock private lateinit var coverContainer: ViewGroup
- private lateinit var coverItem: ImageView
+ @Mock private lateinit var coverContainer1: ViewGroup
+ @Mock private lateinit var coverContainer2: ViewGroup
+ @Mock private lateinit var coverContainer3: ViewGroup
+ private lateinit var coverItem1: ImageView
+ private lateinit var coverItem2: ImageView
+ private lateinit var coverItem3: ImageView
+ private lateinit var recTitle1: TextView
+ private lateinit var recTitle2: TextView
+ private lateinit var recTitle3: TextView
+ private lateinit var recSubtitle1: TextView
+ private lateinit var recSubtitle2: TextView
+ private lateinit var recSubtitle3: TextView
@JvmField @Rule val mockito = MockitoJUnit.rule()
@@ -237,7 +246,6 @@
session.setActive(true)
mediaData = MediaTestUtils.emptyMediaData.copy(
- backgroundColor = BG_COLOR,
artist = ARTIST,
song = TITLE,
packageName = PACKAGE,
@@ -371,19 +379,30 @@
* Initialize elements for the recommendation view holder
*/
private fun initRecommendationViewHolderMocks() {
+ recTitle1 = TextView(context)
+ recTitle2 = TextView(context)
+ recTitle3 = TextView(context)
+ recSubtitle1 = TextView(context)
+ recSubtitle2 = TextView(context)
+ recSubtitle3 = TextView(context)
+
whenever(recommendationViewHolder.recommendations).thenReturn(view)
whenever(recommendationViewHolder.cardIcon).thenReturn(appIcon)
- whenever(recommendationViewHolder.cardText).thenReturn(titleText)
// Add a recommendation item
- coverItem = ImageView(context).also { it.setId(R.id.media_cover1) }
- whenever(coverContainer.id).thenReturn(R.id.media_cover1_container)
- whenever(recommendationViewHolder.mediaCoverItems).thenReturn(listOf(coverItem))
- whenever(recommendationViewHolder.mediaCoverContainers).thenReturn(listOf(coverContainer))
- whenever(recommendationViewHolder.mediaCoverItemsResIds)
- .thenReturn(listOf(R.id.media_cover1))
- whenever(recommendationViewHolder.mediaCoverContainersResIds)
- .thenReturn(listOf(R.id.media_cover1_container))
+ coverItem1 = ImageView(context).also { it.setId(R.id.media_cover1) }
+ coverItem2 = ImageView(context).also { it.setId(R.id.media_cover2) }
+ coverItem3 = ImageView(context).also { it.setId(R.id.media_cover3) }
+
+ whenever(recommendationViewHolder.mediaCoverItems)
+ .thenReturn(listOf(coverItem1, coverItem2, coverItem3))
+ whenever(recommendationViewHolder.mediaCoverContainers)
+ .thenReturn(listOf(coverContainer1, coverContainer2, coverContainer3))
+ whenever(recommendationViewHolder.mediaTitles)
+ .thenReturn(listOf(recTitle1, recTitle2, recTitle3))
+ whenever(recommendationViewHolder.mediaSubtitles).thenReturn(
+ listOf(recSubtitle1, recSubtitle2, recSubtitle3)
+ )
// Long press menu
whenever(recommendationViewHolder.settings).thenReturn(settings)
@@ -396,7 +415,10 @@
// Needed for card and item action click
val mockContext = mock(Context::class.java)
whenever(view.context).thenReturn(mockContext)
- whenever(coverContainer.context).thenReturn(mockContext)
+ whenever(coverContainer1.context).thenReturn(mockContext)
+ whenever(coverContainer2.context).thenReturn(mockContext)
+ whenever(coverContainer3.context).thenReturn(mockContext)
+
}
@After
@@ -678,9 +700,11 @@
MediaAction(icon, null, "custom 0", bg),
MediaAction(icon, Runnable {}, "custom 1", bg)
)
- val state = mediaData.copy(actions = actions,
+ val state = mediaData.copy(
+ actions = actions,
actionsToShowInCompact = listOf(1, 2),
- semanticActions = null)
+ semanticActions = null
+ )
player.attachPlayer(viewHolder)
player.bindPlayer(state, PACKAGE)
@@ -729,11 +753,14 @@
val icon = context.getDrawable(R.drawable.ic_media_play)
val bg = context.getDrawable(R.drawable.ic_media_play_container)
val semanticActions0 = MediaButton(
- playOrPause = MediaAction(mockAvd0, Runnable {}, "play", null))
+ playOrPause = MediaAction(mockAvd0, Runnable {}, "play", null)
+ )
val semanticActions1 = MediaButton(
- playOrPause = MediaAction(mockAvd1, Runnable {}, "pause", null))
+ playOrPause = MediaAction(mockAvd1, Runnable {}, "pause", null)
+ )
val semanticActions2 = MediaButton(
- playOrPause = MediaAction(mockAvd2, Runnable {}, "loading", null))
+ playOrPause = MediaAction(mockAvd2, Runnable {}, "loading", null)
+ )
val state0 = mediaData.copy(semanticActions = semanticActions0)
val state1 = mediaData.copy(semanticActions = semanticActions1)
val state2 = mediaData.copy(semanticActions = semanticActions2)
@@ -773,8 +800,8 @@
assertThat(actionPlayPause.getBackground()).isNull()
verify(mockAvd0, times(1))
.registerAnimationCallback(any(Animatable2.AnimationCallback::class.java))
- verify(mockAvd1, times(1)
- ).registerAnimationCallback(any(Animatable2.AnimationCallback::class.java))
+ verify(mockAvd1, times(1))
+ .registerAnimationCallback(any(Animatable2.AnimationCallback::class.java))
verify(mockAvd2, times(1))
.registerAnimationCallback(any(Animatable2.AnimationCallback::class.java))
verify(mockAvd0, times(1))
@@ -1224,12 +1251,70 @@
player.attachRecommendation(recommendationViewHolder)
player.bindRecommendation(smartspaceData)
- verify(coverContainer).setOnClickListener(captor.capture())
+ verify(coverContainer1).setOnClickListener(captor.capture())
captor.value.onClick(recommendationViewHolder.recommendations)
verify(logger).logRecommendationItemTap(eq(PACKAGE), eq(instanceId), eq(0))
}
+ @Test
+ fun bindRecommendation_hasTitlesAndSubtitles() {
+ player.attachRecommendation(recommendationViewHolder)
+
+ val title1 = "Title1"
+ val title2 = "Title2"
+ val title3 = "Title3"
+ val subtitle1 = "Subtitle1"
+ val subtitle2 = "Subtitle2"
+ val subtitle3 = "Subtitle3"
+
+ val data = smartspaceData.copy(
+ recommendations = listOf(
+ SmartspaceAction.Builder("id1", title1)
+ .setSubtitle(subtitle1)
+ .setIcon(Icon.createWithResource(context, R.drawable.ic_1x_mobiledata))
+ .setExtras(Bundle.EMPTY)
+ .build(),
+ SmartspaceAction.Builder("id2", title2)
+ .setSubtitle(subtitle2)
+ .setIcon(Icon.createWithResource(context, R.drawable.ic_alarm))
+ .setExtras(Bundle.EMPTY)
+ .build(),
+ SmartspaceAction.Builder("id3", title3)
+ .setSubtitle(subtitle3)
+ .setIcon(Icon.createWithResource(context, R.drawable.ic_3g_mobiledata))
+ .setExtras(Bundle.EMPTY)
+ .build()
+ )
+ )
+ player.bindRecommendation(data)
+
+ assertThat(recTitle1.text).isEqualTo(title1)
+ assertThat(recTitle2.text).isEqualTo(title2)
+ assertThat(recTitle3.text).isEqualTo(title3)
+ assertThat(recSubtitle1.text).isEqualTo(subtitle1)
+ assertThat(recSubtitle2.text).isEqualTo(subtitle2)
+ assertThat(recSubtitle3.text).isEqualTo(subtitle3)
+ }
+
+ @Test
+ fun bindRecommendation_noTitle_subtitleNotShown() {
+ player.attachRecommendation(recommendationViewHolder)
+
+ val data = smartspaceData.copy(
+ recommendations = listOf(
+ SmartspaceAction.Builder("id1", "")
+ .setSubtitle("fake subtitle")
+ .setIcon(Icon.createWithResource(context, R.drawable.ic_1x_mobiledata))
+ .setExtras(Bundle.EMPTY)
+ .build()
+ )
+ )
+ player.bindRecommendation(data)
+
+ assertThat(recSubtitle1.text).isEqualTo("")
+ }
+
private fun getScrubbingChangeListener(): SeekBarViewModel.ScrubbingChangeListener =
withArgCaptor { verify(seekBarViewModel).setScrubbingChangeListener(capture()) }
}
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 eacec20..3e335c5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
@@ -57,7 +57,6 @@
private static final String OLD_KEY = "TEST_KEY_OLD";
private static final String APP = "APP";
private static final String PACKAGE = "PKG";
- private static final int BG_COLOR = Color.RED;
private static final String ARTIST = "ARTIST";
private static final String TITLE = "TITLE";
private static final String DEVICE_NAME = "DEVICE_NAME";
@@ -76,7 +75,7 @@
mManager.addListener(mListener);
mMediaData = new MediaData(
- USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null,
+ USER_ID, true, APP, null, ARTIST, TITLE, null,
new ArrayList<>(), new ArrayList<>(), null, PACKAGE, null, null, null, true, null,
MediaData.PLAYBACK_LOCAL, false, KEY, false, false, false, 0L,
InstanceId.fakeInstanceId(-1), -1);
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 7ec31a7..0cbceb6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -277,6 +277,49 @@
}
@Test
+ fun testLoadMediaDataInBg_invalidTokenNoCrash() {
+ val bundle = Bundle()
+ // wrong data type
+ bundle.putParcelable(Notification.EXTRA_MEDIA_SESSION, Bundle())
+ val rcn = SbnBuilder().run {
+ setPkg(SYSTEM_PACKAGE_NAME)
+ modifyNotification(context).also {
+ it.setSmallIcon(android.R.drawable.ic_media_pause)
+ it.addExtras(bundle)
+ it.setStyle(MediaStyle().apply {
+ setRemotePlaybackInfo("Remote device", 0, null)
+ })
+ }
+ build()
+ }
+
+ mediaDataManager.loadMediaDataInBg(KEY, rcn, null)
+ // no crash even though the data structure is incorrect
+ }
+
+ @Test
+ fun testLoadMediaDataInBg_invalidMediaRemoteIntentNoCrash() {
+ val bundle = Bundle()
+ // wrong data type
+ bundle.putParcelable(Notification.EXTRA_MEDIA_REMOTE_INTENT, Bundle())
+ val rcn = SbnBuilder().run {
+ setPkg(SYSTEM_PACKAGE_NAME)
+ modifyNotification(context).also {
+ it.setSmallIcon(android.R.drawable.ic_media_pause)
+ it.addExtras(bundle)
+ it.setStyle(MediaStyle().apply {
+ setMediaSession(session.sessionToken)
+ setRemotePlaybackInfo("Remote device", 0, null)
+ })
+ }
+ build()
+ }
+
+ mediaDataManager.loadMediaDataInBg(KEY, rcn, null)
+ // no crash even though the data structure is incorrect
+ }
+
+ @Test
fun testOnNotificationRemoved_callsListener() {
addNotificationAndLoad()
val data = mediaDataCaptor.value
@@ -467,7 +510,6 @@
cardAction = mediaSmartspaceBaseAction,
recommendations = listOf(mediaRecommendationItem),
dismissIntent = DISMISS_INTENT,
- backgroundColor = 0,
headphoneConnectionTimeMillis = 1234L,
instanceId = InstanceId.fakeInstanceId(instanceId))),
eq(false))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaTestUtils.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTestUtils.kt
index c7ef94e..ae58fe6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaTestUtils.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTestUtils.kt
@@ -7,7 +7,6 @@
val emptyMediaData = MediaData(
userId = 0,
initialized = true,
- backgroundColor = 0,
app = null,
appIcon = null,
artist = null,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SquigglyProgressTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SquigglyProgressTest.kt
index e3cd90b..d087b0f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/SquigglyProgressTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/SquigglyProgressTest.kt
@@ -19,7 +19,7 @@
import org.mockito.ArgumentCaptor
import org.mockito.Captor
import org.mockito.Mock
-import org.mockito.Mockito.anyFloat
+import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
@@ -35,8 +35,7 @@
lateinit var squigglyProgress: SquigglyProgress
@Mock lateinit var canvas: Canvas
- @Captor lateinit var wavePaintCaptor: ArgumentCaptor<Paint>
- @Captor lateinit var linePaintCaptor: ArgumentCaptor<Paint>
+ @Captor lateinit var paintCaptor: ArgumentCaptor<Paint>
@JvmField @Rule val mockitoRule = MockitoJUnit.rule()
@Before
@@ -53,9 +52,7 @@
fun testDrawPathAndLine() {
squigglyProgress.draw(canvas)
- verify(canvas).drawPath(any(), wavePaintCaptor.capture())
- verify(canvas).drawLine(anyFloat(), anyFloat(), anyFloat(), anyFloat(),
- linePaintCaptor.capture())
+ verify(canvas, times(2)).drawPath(any(), paintCaptor.capture())
}
@Test
@@ -69,12 +66,11 @@
fun testStrokeWidth() {
squigglyProgress.draw(canvas)
- verify(canvas).drawPath(any(), wavePaintCaptor.capture())
- verify(canvas).drawLine(anyFloat(), anyFloat(), anyFloat(), anyFloat(),
- linePaintCaptor.capture())
+ verify(canvas, times(2)).drawPath(any(), paintCaptor.capture())
+ val (wavePaint, linePaint) = paintCaptor.getAllValues()
- assertThat(wavePaintCaptor.value.strokeWidth).isEqualTo(strokeWidth)
- assertThat(linePaintCaptor.value.strokeWidth).isEqualTo(strokeWidth)
+ assertThat(wavePaint.strokeWidth).isEqualTo(strokeWidth)
+ assertThat(linePaint.strokeWidth).isEqualTo(strokeWidth)
}
@Test
@@ -82,13 +78,12 @@
squigglyProgress.alpha = alpha
squigglyProgress.draw(canvas)
- verify(canvas).drawPath(any(), wavePaintCaptor.capture())
- verify(canvas).drawLine(anyFloat(), anyFloat(), anyFloat(), anyFloat(),
- linePaintCaptor.capture())
+ verify(canvas, times(2)).drawPath(any(), paintCaptor.capture())
+ val (wavePaint, linePaint) = paintCaptor.getAllValues()
assertThat(squigglyProgress.alpha).isEqualTo(alpha)
- assertThat(wavePaintCaptor.value.alpha).isEqualTo(alpha)
- assertThat(linePaintCaptor.value.alpha).isEqualTo((alpha / 255f * DISABLED_ALPHA).toInt())
+ assertThat(wavePaint.alpha).isEqualTo(alpha)
+ assertThat(linePaint.alpha).isEqualTo((alpha / 255f * DISABLED_ALPHA).toInt())
}
@Test
@@ -96,12 +91,11 @@
squigglyProgress.colorFilter = colorFilter
squigglyProgress.draw(canvas)
- verify(canvas).drawPath(any(), wavePaintCaptor.capture())
- verify(canvas).drawLine(anyFloat(), anyFloat(), anyFloat(), anyFloat(),
- linePaintCaptor.capture())
+ verify(canvas, times(2)).drawPath(any(), paintCaptor.capture())
+ val (wavePaint, linePaint) = paintCaptor.getAllValues()
- assertThat(wavePaintCaptor.value.colorFilter).isEqualTo(colorFilter)
- assertThat(linePaintCaptor.value.colorFilter).isEqualTo(colorFilter)
+ assertThat(wavePaint.colorFilter).isEqualTo(colorFilter)
+ assertThat(linePaint.colorFilter).isEqualTo(colorFilter)
}
@Test
@@ -109,12 +103,11 @@
squigglyProgress.setTint(tint)
squigglyProgress.draw(canvas)
- verify(canvas).drawPath(any(), wavePaintCaptor.capture())
- verify(canvas).drawLine(anyFloat(), anyFloat(), anyFloat(), anyFloat(),
- linePaintCaptor.capture())
+ verify(canvas, times(2)).drawPath(any(), paintCaptor.capture())
+ val (wavePaint, linePaint) = paintCaptor.getAllValues()
- assertThat(wavePaintCaptor.value.color).isEqualTo(tint)
- assertThat(linePaintCaptor.value.color).isEqualTo(
+ assertThat(wavePaint.color).isEqualTo(tint)
+ assertThat(linePaint.color).isEqualTo(
ColorUtils.setAlphaComponent(tint, DISABLED_ALPHA))
}
}
\ No newline at end of file
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 4fbdb7c..a518b80 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -190,7 +190,7 @@
QSFragment fragment = resumeAndGetFragment();
enableSplitShade();
setStatusBarState(StatusBarState.KEYGUARD);
- when(mQSPanelController.bouncerInTransit()).thenReturn(false);
+ when(mQSPanelController.isBouncerInTransit()).thenReturn(false);
int transitionPxAmount = 123;
float transitionProgress = 0.5f;
@@ -206,7 +206,7 @@
QSFragment fragment = resumeAndGetFragment();
enableSplitShade();
setStatusBarState(StatusBarState.KEYGUARD);
- when(mQSPanelController.bouncerInTransit()).thenReturn(true);
+ when(mQSPanelController.isBouncerInTransit()).thenReturn(true);
int transitionPxAmount = 123;
float transitionProgress = 0.5f;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
index 689de50..69d3f8b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
@@ -61,7 +61,7 @@
whenever(brightnessSliderFactory.create(any(), any())).thenReturn(brightnessSlider)
whenever(brightnessControllerFactory.create(any())).thenReturn(brightnessController)
whenever(qsPanel.resources).thenReturn(mContext.orCreateTestableResources.resources)
- whenever(statusBarKeyguardViewManager.bouncerIsInTransit()).thenReturn(false)
+ whenever(statusBarKeyguardViewManager.isBouncerInTransit()).thenReturn(false)
controller = QSPanelController(
qsPanel,
@@ -109,10 +109,10 @@
}
@Test
- fun testBouncerIsInTransit() {
- whenever(statusBarKeyguardViewManager.bouncerIsInTransit()).thenReturn(true)
- assertThat(controller.bouncerInTransit()).isEqualTo(true)
- whenever(statusBarKeyguardViewManager.bouncerIsInTransit()).thenReturn(false)
- assertThat(controller.bouncerInTransit()).isEqualTo(false)
+ fun testIsBouncerInTransit() {
+ whenever(statusBarKeyguardViewManager.isBouncerInTransit()).thenReturn(true)
+ assertThat(controller.isBouncerInTransit()).isEqualTo(true)
+ whenever(statusBarKeyguardViewManager.isBouncerInTransit()).thenReturn(false)
+ assertThat(controller.isBouncerInTransit()).isEqualTo(false)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
index cf97bda..616f894 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
@@ -21,12 +21,15 @@
import android.testing.TestableLooper;
import android.view.View;
import android.widget.LinearLayout;
+import android.widget.Switch;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import androidx.test.filters.SmallTest;
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.internal.logging.UiEventLogger;
+import com.android.settingslib.wifi.WifiEnterpriseRestrictionUtils;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -42,6 +45,7 @@
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoSession;
import java.util.List;
@@ -79,12 +83,16 @@
private LinearLayout mEthernet;
private LinearLayout mMobileDataToggle;
private LinearLayout mWifiToggle;
+ private Switch mWifiToggleSwitch;
+ private TextView mWifiToggleSummary;
private LinearLayout mConnectedWifi;
private RecyclerView mWifiList;
private LinearLayout mSeeAll;
private LinearLayout mWifiScanNotify;
private TextView mAirplaneModeSummaryText;
+ private MockitoSession mMockitoSession;
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
@@ -101,6 +109,15 @@
.thenReturn(MOBILE_NETWORK_SUMMARY);
when(mInternetDialogController.getWifiManager()).thenReturn(mWifiManager);
+ mMockitoSession = ExtendedMockito.mockitoSession()
+ .spyStatic(WifiEnterpriseRestrictionUtils.class)
+ .startMocking();
+ when(WifiEnterpriseRestrictionUtils.isChangeWifiStateAllowed(mContext)).thenReturn(true);
+
+ createInternetDialog();
+ }
+
+ private void createInternetDialog() {
mInternetDialog = new InternetDialog(mContext, mock(InternetDialogFactory.class),
mInternetDialogController, true, true, true, mock(UiEventLogger.class), mHandler,
mBgExecutor, mKeyguard);
@@ -114,6 +131,8 @@
mEthernet = mDialogView.requireViewById(R.id.ethernet_layout);
mMobileDataToggle = mDialogView.requireViewById(R.id.mobile_network_layout);
mWifiToggle = mDialogView.requireViewById(R.id.turn_on_wifi_layout);
+ mWifiToggleSwitch = mDialogView.requireViewById(R.id.wifi_toggle);
+ mWifiToggleSummary = mDialogView.requireViewById(R.id.wifi_toggle_summary);
mConnectedWifi = mDialogView.requireViewById(R.id.wifi_connected_layout);
mWifiList = mDialogView.requireViewById(R.id.wifi_list_layout);
mSeeAll = mDialogView.requireViewById(R.id.see_all_layout);
@@ -124,6 +143,7 @@
@After
public void tearDown() {
mInternetDialog.dismissDialog();
+ mMockitoSession.finishMocking();
}
@Test
@@ -411,6 +431,33 @@
}
@Test
+ public void updateDialog_disallowChangeWifiState_disableWifiSwitch() {
+ mInternetDialog.dismissDialog();
+ when(WifiEnterpriseRestrictionUtils.isChangeWifiStateAllowed(mContext)).thenReturn(false);
+ createInternetDialog();
+
+ mInternetDialog.updateDialog(false);
+
+ // Disable Wi-Fi switch and show restriction message in summary.
+ assertThat(mWifiToggleSwitch.isEnabled()).isFalse();
+ assertThat(mWifiToggleSummary.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mWifiToggleSummary.getText().length()).isNotEqualTo(0);
+ }
+
+ @Test
+ public void updateDialog_allowChangeWifiState_enableWifiSwitch() {
+ mInternetDialog.dismissDialog();
+ when(WifiEnterpriseRestrictionUtils.isChangeWifiStateAllowed(mContext)).thenReturn(true);
+ createInternetDialog();
+
+ mInternetDialog.updateDialog(false);
+
+ // Enable Wi-Fi switch and hide restriction message in summary.
+ assertThat(mWifiToggleSwitch.isEnabled()).isTrue();
+ assertThat(mWifiToggleSummary.getVisibility()).isEqualTo(View.GONE);
+ }
+
+ @Test
public void updateDialog_wifiOn_hideWifiScanNotify() {
// The preconditions WiFi ON and WiFi entries are already in setUp()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
index 03c22b3..1b1f4e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
@@ -32,6 +32,7 @@
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
+import android.app.Notification;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.ApplicationInfo;
@@ -41,6 +42,7 @@
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Icon;
+import android.os.Bundle;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
@@ -170,4 +172,16 @@
mIconView.getIcon(largeIcon);
// No crash? good
}
+
+ @Test
+ public void testContentDescForNotification_invalidAi_noCrash() {
+ Notification n = new Notification.Builder(mContext, "test")
+ .setSmallIcon(0)
+ .build();
+ // should be ApplicationInfo
+ n.extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, new Bundle());
+ StatusBarIconView.contentDescForNotification(mContext, n);
+
+ // no crash, good
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
index 241451e..5804ad4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
@@ -229,6 +229,41 @@
assertTrue(entry.isLastMessageFromReply());
}
+ @Test
+ public void notificationDataEntry_testIsLastMessageFromReply_invalidPerson_noCrash() {
+ Person.Builder person = new Person.Builder()
+ .setName("name")
+ .setKey("abc")
+ .setUri("uri")
+ .setBot(true);
+
+ Bundle bundle = new Bundle();
+ // should be Person.class
+ bundle.putParcelable(Notification.EXTRA_MESSAGING_PERSON, new Bundle());
+ Bundle[] messagesBundle = new Bundle[]{new Notification.MessagingStyle.Message(
+ "text", 0, person.build()).toBundle()};
+ bundle.putParcelableArray(Notification.EXTRA_MESSAGES, messagesBundle);
+
+ Notification notification = new Notification.Builder(mContext, "test")
+ .addExtras(bundle)
+ .build();
+
+ NotificationEntry entry = new NotificationEntryBuilder()
+ .setPkg("pkg")
+ .setOpPkg("pkg")
+ .setTag("tag")
+ .setNotification(notification)
+ .setUser(mContext.getUser())
+ .setOverrideGroupKey("")
+ .build();
+ entry.setHasSentReply();
+
+ entry.isLastMessageFromReply();
+
+ // no crash, good
+ }
+
+
private Notification.Action createContextualAction(String title) {
return new Notification.Action.Builder(
Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapperTest.java
new file mode 100644
index 0000000..509ba41
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationBigPictureTemplateViewWrapperTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2022 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.wrapper;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.Notification;
+import android.content.Context;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidTestingRunner.class)
+@SmallTest
+@RunWithLooper
+public class NotificationBigPictureTemplateViewWrapperTest extends SysuiTestCase {
+
+ private View mView;
+ private ExpandableNotificationRow mRow;
+
+
+ @Before
+ public void setup() throws Exception {
+ allowTestableLooperAsMainThread();
+ NotificationTestHelper helper = new NotificationTestHelper(
+ mContext,
+ mDependency,
+ TestableLooper.get(this));
+ mView = LayoutInflater.from(mContext).inflate(
+ com.android.internal.R.layout.notification_template_material_big_picture, null);
+ mRow = helper.createRow();
+ }
+
+ @Test
+ public void invalidLargeIconBig_noCrash() {
+ NotificationViewWrapper wrapper = new NotificationBigPictureTemplateViewWrapper(
+ mContext, mView, mRow);
+ // should be Icon.class
+ mRow.getEntry().getSbn().getNotification().setSmallIcon(
+ Icon.createWithResource(mContext, 0));
+ mRow.getEntry().getSbn().getNotification().extras.putParcelable(
+ Notification.EXTRA_LARGE_ICON_BIG, new Bundle());
+ wrapper.onContentUpdated(mRow);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
index 5d16036..4270d72 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
@@ -144,7 +144,7 @@
}
private fun setFractionToShade(fraction: Float) {
- shelf.setFractionToShade(fraction)
+ whenever(ambientState.fractionToShade).thenReturn(fraction)
}
private fun setOnLockscreen(isOnLockscreen: Boolean) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 7a92b96..077f6bf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -64,6 +64,7 @@
import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
import org.junit.Assert;
@@ -104,6 +105,7 @@
@Mock private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
@Mock private NotificationShelf mNotificationShelf;
@Mock private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
+ @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@Before
@UiThreadTest
@@ -111,7 +113,8 @@
allowTestableLooperAsMainThread();
// Interact with real instance of AmbientState.
- mAmbientState = new AmbientState(mContext, mNotificationSectionsManager, mBypassController);
+ mAmbientState = new AmbientState(mContext, mNotificationSectionsManager, mBypassController,
+ mStatusBarKeyguardViewManager);
// Inject dependencies before initializing the layout
mDependency.injectTestDependency(SysuiStatusBarStateController.class, mBarState);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
index 968e16a..c3658ba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
@@ -23,6 +23,8 @@
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.LockscreenShadeTransitionController
+import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
@@ -44,7 +46,7 @@
class NotificationStackSizeCalculatorTest : SysuiTestCase() {
@Mock private lateinit var sysuiStatusBarStateController: SysuiStatusBarStateController
-
+ @Mock private lateinit var lockscreenShadeTransitionController: LockscreenShadeTransitionController
@Mock private lateinit var stackLayout: NotificationStackScrollLayout
private val testableResources = mContext.getOrCreateTestableResources()
@@ -63,6 +65,7 @@
sizeCalculator =
NotificationStackSizeCalculator(
statusBarStateController = sysuiStatusBarStateController,
+ lockscreenShadeTransitionController = lockscreenShadeTransitionController,
testableResources.resources)
}
@@ -155,6 +158,55 @@
assertThat(height).isAtMost(availableSpace)
}
+ @Test
+ fun onLockscreen_onKeyguard_AndNotGoingToShade_returnsTrue() {
+ whenever(sysuiStatusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
+ whenever(lockscreenShadeTransitionController.fractionToShade).thenReturn(0f)
+ assertThat(sizeCalculator.onLockscreen()).isTrue()
+ }
+
+ @Test
+ fun onLockscreen_goingToShade_returnsFalse() {
+ whenever(sysuiStatusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
+ whenever(lockscreenShadeTransitionController.fractionToShade).thenReturn(0.5f)
+ assertThat(sizeCalculator.onLockscreen()).isFalse()
+ }
+
+ @Test
+ fun onLockscreen_notOnLockscreen_returnsFalse() {
+ whenever(sysuiStatusBarStateController.state).thenReturn(StatusBarState.SHADE)
+ whenever(lockscreenShadeTransitionController.fractionToShade).thenReturn(1f)
+ assertThat(sizeCalculator.onLockscreen()).isFalse()
+ }
+
+ @Test
+ fun spaceNeeded_onLockscreen_usesMinHeight() {
+ setGapHeight(0f)
+ // No divider height since we're testing one element where index = 0
+
+ val expandableView = createMockRow(rowHeight)
+ whenever(expandableView.getMinHeight(any())).thenReturn(5)
+ whenever(expandableView.intrinsicHeight).thenReturn(10)
+
+ val space = sizeCalculator.spaceNeeded(expandableView, visibleIndex = 0,
+ previousView = null, stack = stackLayout, onLockscreen = true)
+ assertThat(space).isEqualTo(5)
+ }
+
+ @Test
+ fun spaceNeeded_notOnLockscreen_usesIntrinsicHeight() {
+ setGapHeight(0f)
+ // No divider height since we're testing one element where index = 0
+
+ val expandableView = createMockRow(rowHeight)
+ whenever(expandableView.getMinHeight(any())).thenReturn(5)
+ whenever(expandableView.intrinsicHeight).thenReturn(10)
+
+ val space = sizeCalculator.spaceNeeded(expandableView, visibleIndex = 0,
+ previousView = null, stack = stackLayout, onLockscreen = false)
+ assertThat(space).isEqualTo(10)
+ }
+
private fun computeMaxKeyguardNotifications(
rows: List<ExpandableView>,
availableSpace: Float,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
index 1da9bbc..1f90d0c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
@@ -1,5 +1,6 @@
package com.android.systemui.statusbar.notification.stack
+import android.annotation.DimenRes
import android.widget.FrameLayout
import androidx.test.filters.SmallTest
import com.android.systemui.R
@@ -8,6 +9,7 @@
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.BypassController
import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.SectionProvider
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
@@ -21,10 +23,22 @@
private val stackScrollAlgorithm = StackScrollAlgorithm(context, hostView)
private val expandableViewState = ExpandableViewState()
private val notificationRow = mock(ExpandableNotificationRow::class.java)
+ private val mStatusBarKeyguardViewManager = mock(StatusBarKeyguardViewManager::class.java)
+
private val ambientState = AmbientState(
- context,
- SectionProvider { _, _ -> false },
- BypassController { false })
+ context,
+ SectionProvider { _, _ -> false },
+ BypassController { false },
+ mStatusBarKeyguardViewManager
+ )
+
+ private val testableResources = mContext.orCreateTestableResources
+
+ private fun px(@DimenRes id: Int): Float =
+ testableResources.resources.getDimensionPixelSize(id).toFloat()
+
+ private val bigGap = px(R.dimen.notification_section_divider_height)
+ private val smallGap = px(R.dimen.notification_section_divider_height_lockscreen)
@Before
fun setUp() {
@@ -75,4 +89,25 @@
val centeredY = ambientState.stackY + fullHeight / 2f - emptyShadeView.height / 2f
assertThat(emptyShadeView.viewState?.yTranslation).isEqualTo(centeredY)
}
+
+ @Test
+ fun getGapForLocation_onLockscreen_returnsSmallGap() {
+ val gap = stackScrollAlgorithm.getGapForLocation(
+ /* fractionToShade= */ 0f, /* onKeyguard= */ true)
+ assertThat(gap).isEqualTo(smallGap)
+ }
+
+ @Test
+ fun getGapForLocation_goingToShade_interpolatesGap() {
+ val gap = stackScrollAlgorithm.getGapForLocation(
+ /* fractionToShade= */ 0.5f, /* onKeyguard= */ true)
+ assertThat(gap).isEqualTo(smallGap * 0.5f + bigGap * 0.5f)
+ }
+
+ @Test
+ fun getGapForLocation_notOnLockscreen_returnsBigGap() {
+ val gap = stackScrollAlgorithm.getGapForLocation(
+ /* fractionToShade= */ 0f, /* onKeyguard= */ false)
+ assertThat(gap).isEqualTo(bigGap)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
index 09773d3..05fb1f59 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
@@ -80,6 +80,7 @@
import com.android.keyguard.dagger.KeyguardStatusBarViewComponent;
import com.android.keyguard.dagger.KeyguardStatusViewComponent;
import com.android.keyguard.dagger.KeyguardUserSwitcherComponent;
+import com.android.systemui.DejankUtils;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
@@ -352,6 +353,7 @@
mKeyguardStatusView = new KeyguardStatusView(mContext);
mKeyguardStatusView.setId(R.id.keyguard_status_view);
+ DejankUtils.setImmediate(true);
when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(false);
when(mHeadsUpCallback.getContext()).thenReturn(mContext);
@@ -942,6 +944,29 @@
}
@Test
+ public void testUnlockHintAnimation_runs_whenNotInPowerSaveMode_andDozeAmountIsZero() {
+ when(mPowerManager.isPowerSaveMode()).thenReturn(false);
+ when(mAmbientState.getDozeAmount()).thenReturn(0f);
+ mNotificationPanelViewController.startUnlockHintAnimation();
+ assertThat(mNotificationPanelViewController.mHintAnimationRunning).isTrue();
+ }
+
+ @Test
+ public void testUnlockHintAnimation_doesNotRun_inPowerSaveMode() {
+ when(mPowerManager.isPowerSaveMode()).thenReturn(true);
+ mNotificationPanelViewController.startUnlockHintAnimation();
+ assertThat(mNotificationPanelViewController.mHintAnimationRunning).isFalse();
+ }
+
+ @Test
+ public void testUnlockHintAnimation_doesNotRun_whenDozeAmountNotZero() {
+ when(mPowerManager.isPowerSaveMode()).thenReturn(false);
+ when(mAmbientState.getDozeAmount()).thenReturn(0.5f);
+ mNotificationPanelViewController.startUnlockHintAnimation();
+ assertThat(mNotificationPanelViewController.mHintAnimationRunning).isFalse();
+ }
+
+ @Test
public void setKeyguardStatusBarAlpha_setsAlphaOnKeyguardStatusBarController() {
float statusBarAlpha = 0.5f;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 69d7932..ff2c05b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -1238,7 +1238,7 @@
@Test
public void expansionNotificationAlpha_shadeLocked_bouncerActive_usesBouncerInterpolator() {
- when(mStatusBarKeyguardViewManager.bouncerIsInTransit()).thenReturn(true);
+ when(mStatusBarKeyguardViewManager.isBouncerInTransit()).thenReturn(true);
mScrimController.transitionTo(ScrimState.SHADE_LOCKED);
@@ -1254,7 +1254,7 @@
@Test
public void expansionNotificationAlpha_shadeLocked_bouncerNotActive_usesShadeInterpolator() {
- when(mStatusBarKeyguardViewManager.bouncerIsInTransit()).thenReturn(false);
+ when(mStatusBarKeyguardViewManager.isBouncerInTransit()).thenReturn(false);
mScrimController.transitionTo(ScrimState.SHADE_LOCKED);
@@ -1269,7 +1269,7 @@
@Test
public void notificationAlpha_unnocclusionAnimating_bouncerActive_usesKeyguardNotifAlpha() {
- when(mStatusBarKeyguardViewManager.bouncerIsInTransit()).thenReturn(true);
+ when(mStatusBarKeyguardViewManager.isBouncerInTransit()).thenReturn(true);
mScrimController.transitionTo(ScrimState.KEYGUARD);
mScrimController.setUnocclusionAnimationRunning(true);
@@ -1290,7 +1290,7 @@
@Test
public void notificationAlpha_unnocclusionAnimating_bouncerNotActive_usesKeyguardNotifAlpha() {
- when(mStatusBarKeyguardViewManager.bouncerIsInTransit()).thenReturn(false);
+ when(mStatusBarKeyguardViewManager.isBouncerInTransit()).thenReturn(false);
mScrimController.transitionTo(ScrimState.KEYGUARD);
mScrimController.setUnocclusionAnimationRunning(true);
@@ -1311,7 +1311,7 @@
@Test
public void notificationAlpha_inKeyguardState_bouncerActive_usesInvertedBouncerInterpolator() {
- when(mStatusBarKeyguardViewManager.bouncerIsInTransit()).thenReturn(true);
+ when(mStatusBarKeyguardViewManager.isBouncerInTransit()).thenReturn(true);
mScrimController.transitionTo(ScrimState.KEYGUARD);
@@ -1330,7 +1330,7 @@
@Test
public void notificationAlpha_inKeyguardState_bouncerNotActive_usesInvertedShadeInterpolator() {
- when(mStatusBarKeyguardViewManager.bouncerIsInTransit()).thenReturn(false);
+ when(mStatusBarKeyguardViewManager.isBouncerInTransit()).thenReturn(false);
mScrimController.transitionTo(ScrimState.KEYGUARD);
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 90cbf54..2b01872 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
@@ -438,12 +438,12 @@
}
@Test
- public void testBouncerIsInTransit() {
+ public void testIsBouncerInTransit() {
when(mBouncer.inTransit()).thenReturn(true);
- Truth.assertThat(mStatusBarKeyguardViewManager.bouncerIsInTransit()).isTrue();
+ Truth.assertThat(mStatusBarKeyguardViewManager.isBouncerInTransit()).isTrue();
when(mBouncer.inTransit()).thenReturn(false);
- Truth.assertThat(mStatusBarKeyguardViewManager.bouncerIsInTransit()).isFalse();
+ Truth.assertThat(mStatusBarKeyguardViewManager.isBouncerInTransit()).isFalse();
mBouncer = null;
- Truth.assertThat(mStatusBarKeyguardViewManager.bouncerIsInTransit()).isFalse();
+ Truth.assertThat(mStatusBarKeyguardViewManager.isBouncerInTransit()).isFalse();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java
index 2c461ae..3032ff1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java
@@ -104,7 +104,7 @@
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
mManager = new ThemeOverlayApplier(mOverlayManager,
- MoreExecutors.directExecutor(), MoreExecutors.directExecutor(),
+ MoreExecutors.directExecutor(),
LAUNCHER_PACKAGE, THEMEPICKER_PACKAGE, mDumpManager) {
@Override
protected OverlayManagerTransaction.Builder getTransactionBuilder() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
index 7ac2434..05a8f0a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
@@ -78,6 +78,9 @@
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
+ overrideResource(
+ com.android.internal.R.integer.config_unfoldTransitionHalfFoldedTimeout,
+ HALF_OPENED_TIMEOUT_MILLIS.toInt())
deviceStates = FoldableTestUtils.findDeviceStates(context)
foldStateProvider =
@@ -319,4 +322,8 @@
private fun sendHingeAngleEvent(angle: Int) {
hingeAngleCaptor.value.accept(angle.toFloat())
}
+
+ companion object {
+ private const val HALF_OPENED_TIMEOUT_MILLIS = 300L
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
index 3d55488..b30c20d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
@@ -21,11 +21,16 @@
import android.hardware.usb.UsbAccessory
import android.hardware.usb.UsbManager
import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
import android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS
import androidx.test.filters.SmallTest
import androidx.test.rule.ActivityTestRule
+import androidx.test.runner.intercepting.SingleActivityFactory
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
+
+import javax.inject.Inject
+
import org.junit.After
import org.junit.Before
import org.junit.Rule
@@ -37,14 +42,26 @@
*/
@RunWith(AndroidTestingRunner::class)
@SmallTest
+@TestableLooper.RunWithLooper
class UsbPermissionActivityTest : SysuiTestCase() {
- class UsbPermissionActivityTestable : UsbPermissionActivity()
+ private var mMessage: UsbAudioWarningDialogMessage = UsbAudioWarningDialogMessage()
+
+ open class UsbPermissionActivityTestable @Inject constructor (
+ val message: UsbAudioWarningDialogMessage
+ )
+ : UsbPermissionActivity(UsbAudioWarningDialogMessage())
@Rule
@JvmField
var activityRule = ActivityTestRule<UsbPermissionActivityTestable>(
- UsbPermissionActivityTestable::class.java, false, false)
+ object : SingleActivityFactory<UsbPermissionActivityTestable>(
+ UsbPermissionActivityTestable::class.java
+ ) {
+ override fun create(intent: Intent?): UsbPermissionActivityTestable {
+ return UsbPermissionActivityTestable(mMessage)
+ }
+ }, false, false)
private val activityIntent = Intent(mContext, UsbPermissionActivityTestable::class.java)
.apply {
@@ -72,6 +89,7 @@
@Before
fun setUp() {
+ UsbPermissionActivityTestable(mMessage)
activityRule.launchActivity(activityIntent)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/leak/LeakDetectorTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/leak/LeakDetectorTest.java
index 3ee1a27..8f93433 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/leak/LeakDetectorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/leak/LeakDetectorTest.java
@@ -52,6 +52,8 @@
private Object mObject;
private Collection<?> mCollection;
+
+
private CollectionWaiter trackObjectWith(Consumer<Object> tracker) {
mObject = new Object();
CollectionWaiter collectionWaiter = ReferenceTestUtils.createCollectionWaiter(mObject);
@@ -69,7 +71,9 @@
@Before
public void setup() {
- mLeakDetector = LeakDetector.create(Mockito.mock(DumpManager.class));
+ TrackedCollections collections = new TrackedCollections();
+ mLeakDetector = new LeakDetector(collections, new TrackedGarbage(collections),
+ new TrackedObjects(collections), Mockito.mock(DumpManager.class));
// Note: Do not try to factor out object / collection waiter creation. The optimizer will
// try and cache accesses to fields and thus create a GC root for the duration of the test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java
index 01769e5..b1950ea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java
@@ -20,6 +20,7 @@
import static android.view.View.VISIBLE;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -323,6 +324,7 @@
assertEquals(GONE, mWalletView.getCardCarousel().getVisibility());
assertEquals(VISIBLE, mWalletView.getEmptyStateView().getVisibility());
assertEquals(GONE, mWalletView.getErrorView().getVisibility());
+ assertTrue(mWalletView.getAppButton().hasOnClickListeners());
}
@Test
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index bc4b2a6..5acae48 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -154,7 +154,7 @@
private static final String TAG = "AppWidgetServiceImpl";
private static final boolean DEBUG = false;
- private static final boolean DEBUG_PROVIDER_INFO_CACHE = true;
+ static final boolean DEBUG_PROVIDER_INFO_CACHE = true;
private static final String OLD_KEYGUARD_HOST_PACKAGE = "android";
private static final String NEW_KEYGUARD_HOST_PACKAGE = "com.android.keyguard";
@@ -2001,6 +2001,7 @@
}
}
+ @GuardedBy("mLock")
private void scheduleNotifyProviderChangedLocked(Widget widget) {
long requestId = UPDATE_COUNTER.incrementAndGet();
if (widget != null) {
@@ -2330,6 +2331,7 @@
sendBroadcastAsUser(intent, widget.provider.id.getProfile());
}
+ @GuardedBy("mLock")
private void registerForBroadcastsLocked(Provider provider, int[] appWidgetIds) {
AppWidgetProviderInfo info = provider.getInfoLocked(mContext);
if (info.updatePeriodMillis > 0) {
@@ -3433,6 +3435,7 @@
*
* @return whether any providers were updated
*/
+ @GuardedBy("mLock")
private boolean updateProvidersForPackageLocked(String packageName, int userId,
Set<ProviderId> removedProviders) {
boolean providersUpdated = false;
@@ -4218,6 +4221,7 @@
/**
* Adds all pending updates in {@param outUpdates} keys by the update time.
*/
+ @GuardedBy("mLock")
public void getPendingUpdatesForIdLocked(Context context, int appWidgetId,
LongSparseArray<PendingHostUpdate> outUpdates) {
long updateSequenceNo = lastWidgetUpdateSequenceNo;
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java
index 297575c..6a5dcc8 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java
@@ -22,6 +22,7 @@
import android.content.ComponentName;
import android.os.Build;
import android.text.TextUtils;
+import android.util.Slog;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
@@ -33,6 +34,8 @@
*/
public class AppWidgetXmlUtil {
+ private static final String TAG = "AppWidgetXmlUtil";
+
private static final String ATTR_MIN_WIDTH = "min_width";
private static final String ATTR_MIN_HEIGHT = "min_height";
private static final String ATTR_MIN_RESIZE_WIDTH = "min_resize_width";
@@ -77,7 +80,11 @@
if (info.configure != null) {
out.attribute(null, ATTR_CONFIGURE, info.configure.flattenToShortString());
}
- out.attribute(null, ATTR_LABEL, info.label);
+ if (info.label != null) {
+ out.attribute(null, ATTR_LABEL, info.label);
+ } else if (AppWidgetServiceImpl.DEBUG_PROVIDER_INFO_CACHE) {
+ Slog.e(TAG, "Label is empty in " + info.provider);
+ }
out.attributeInt(null, ATTR_ICON, info.icon);
out.attributeInt(null, ATTR_PREVIEW_IMAGE, info.previewImage);
out.attributeInt(null, ATTR_PREVIEW_LAYOUT, info.previewLayout);
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index ac0944b..b4c107c 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -671,6 +671,9 @@
association = AssociationInfo.builder(association)
.setNotifyOnDeviceNearby(active)
.build();
+ // Do not need to call {@link BleCompanionDeviceScanner#restartScan()} since it will
+ // trigger {@link BleCompanionDeviceScanner#restartScan(int, AssociationInfo)} when
+ // an application sets/unsets the mNotifyOnDeviceNearby flag.
mAssociationStore.updateAssociation(association);
// TODO(b/218615198): correctly handle the case when the device is currently present.
diff --git a/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java b/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java
index 33301b1..ad09f7c 100644
--- a/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java
+++ b/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java
@@ -194,6 +194,8 @@
// Collect MAC addresses from all associations.
final Set<String> macAddresses = new HashSet<>();
for (AssociationInfo association : mAssociationStore.getAssociations()) {
+ if (!association.isNotifyOnDeviceNearby()) continue;
+
// Beware that BT stack does not consider low-case MAC addresses valid, while
// MacAddress.toString() return a low-case String.
final String macAddress = association.getDeviceMacAddressAsString();
diff --git a/services/core/java/com/android/server/BinaryTransparencyService.java b/services/core/java/com/android/server/BinaryTransparencyService.java
index 1f8ef82..877ee82 100644
--- a/services/core/java/com/android/server/BinaryTransparencyService.java
+++ b/services/core/java/com/android/server/BinaryTransparencyService.java
@@ -441,6 +441,7 @@
final JobInfo jobInfo = new JobInfo.Builder(COMPUTE_APEX_MODULE_SHA256_JOB_ID,
new ComponentName(context, UpdateMeasurementsJobService.class))
.setRequiresDeviceIdle(true)
+ .setRequiresCharging(true)
.build();
if (jobScheduler.schedule(jobInfo) != JobScheduler.RESULT_SUCCESS) {
Slog.e(TAG, "Failed to schedule job to update binary measurements.");
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 210532a..eefeee3 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -87,6 +87,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -172,7 +173,7 @@
@NonNull private final VcnNetworkProvider mNetworkProvider;
@NonNull private final TelephonySubscriptionTrackerCallback mTelephonySubscriptionTrackerCb;
@NonNull private final TelephonySubscriptionTracker mTelephonySubscriptionTracker;
- @NonNull private final BroadcastReceiver mPkgChangeReceiver;
+ @NonNull private final BroadcastReceiver mVcnBroadcastReceiver;
@NonNull
private final TrackingNetworkCallback mTrackingNetworkCallback = new TrackingNetworkCallback();
@@ -217,28 +218,17 @@
mConfigDiskRwHelper = mDeps.newPersistableBundleLockingReadWriteHelper(VCN_CONFIG_FILE);
- mPkgChangeReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
-
- if (Intent.ACTION_PACKAGE_ADDED.equals(action)
- || Intent.ACTION_PACKAGE_REPLACED.equals(action)
- || Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
- mTelephonySubscriptionTracker.handleSubscriptionsChanged();
- } else {
- Log.wtf(TAG, "received unexpected intent: " + action);
- }
- }
- };
+ mVcnBroadcastReceiver = new VcnBroadcastReceiver();
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ intentFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
+ intentFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
intentFilter.addDataScheme("package");
mContext.registerReceiver(
- mPkgChangeReceiver, intentFilter, null /* broadcastPermission */, mHandler);
+ mVcnBroadcastReceiver, intentFilter, null /* broadcastPermission */, mHandler);
// Run on handler to ensure I/O does not block system server startup
mHandler.post(() -> {
@@ -443,6 +433,53 @@
return Objects.equals(subGrp, snapshot.getActiveDataSubscriptionGroup());
}
+ private class VcnBroadcastReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+
+ switch (action) {
+ case Intent.ACTION_PACKAGE_ADDED: // Fallthrough
+ case Intent.ACTION_PACKAGE_REPLACED: // Fallthrough
+ case Intent.ACTION_PACKAGE_REMOVED:
+ // Reevaluate subscriptions
+ mTelephonySubscriptionTracker.handleSubscriptionsChanged();
+
+ break;
+ case Intent.ACTION_PACKAGE_FULLY_REMOVED:
+ case Intent.ACTION_PACKAGE_DATA_CLEARED:
+ final String pkgName = intent.getData().getSchemeSpecificPart();
+
+ if (pkgName == null || pkgName.isEmpty()) {
+ logWtf("Package name was empty or null for intent with action" + action);
+ return;
+ }
+
+ // Clear configs for the packages that had data cleared, or removed.
+ synchronized (mLock) {
+ final List<ParcelUuid> toRemove = new ArrayList<>();
+ for (Entry<ParcelUuid, VcnConfig> entry : mConfigs.entrySet()) {
+ if (pkgName.equals(entry.getValue().getProvisioningPackageName())) {
+ toRemove.add(entry.getKey());
+ }
+ }
+
+ for (ParcelUuid subGrp : toRemove) {
+ stopAndClearVcnConfigInternalLocked(subGrp);
+ }
+
+ if (!toRemove.isEmpty()) {
+ writeConfigsToDiskLocked();
+ }
+ }
+
+ break;
+ default:
+ Slog.wtf(TAG, "received unexpected intent: " + action);
+ }
+ }
+ }
+
private class VcnSubscriptionTrackerCallback implements TelephonySubscriptionTrackerCallback {
/**
* Handles subscription group changes, as notified by {@link TelephonySubscriptionTracker}
@@ -504,6 +541,7 @@
final Map<ParcelUuid, Set<Integer>> currSubGrpMappings =
getSubGroupToSubIdMappings(mLastSnapshot);
if (!currSubGrpMappings.equals(oldSubGrpMappings)) {
+ garbageCollectAndWriteVcnConfigsLocked();
notifyAllPolicyListenersLocked();
}
}
@@ -645,6 +683,39 @@
});
}
+ private void enforceCarrierPrivilegeOrProvisioningPackage(
+ @NonNull ParcelUuid subscriptionGroup, @NonNull String pkg) {
+ // Only apps running in the primary (system) user are allowed to configure the VCN. This is
+ // in line with Telephony's behavior with regards to binding to a Carrier App provided
+ // CarrierConfigService.
+ enforcePrimaryUser();
+
+ if (isProvisioningPackageForConfig(subscriptionGroup, pkg)) {
+ return;
+ }
+
+ // Must NOT be called from cleared binder identity, since this checks user calling identity
+ enforceCallingUserAndCarrierPrivilege(subscriptionGroup, pkg);
+ }
+
+ private boolean isProvisioningPackageForConfig(
+ @NonNull ParcelUuid subscriptionGroup, @NonNull String pkg) {
+ // Try-finally to return early if matching owned subscription found.
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mLock) {
+ final VcnConfig config = mConfigs.get(subscriptionGroup);
+ if (config != null && pkg.equals(config.getProvisioningPackageName())) {
+ return true;
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+
+ return false;
+ }
+
/**
* Clears the VcnManagementService for a given subscription group.
*
@@ -658,31 +729,56 @@
mContext.getSystemService(AppOpsManager.class)
.checkPackage(mDeps.getBinderCallingUid(), opPkgName);
- enforceCallingUserAndCarrierPrivilege(subscriptionGroup, opPkgName);
+ enforceCarrierPrivilegeOrProvisioningPackage(subscriptionGroup, opPkgName);
Binder.withCleanCallingIdentity(() -> {
synchronized (mLock) {
- mConfigs.remove(subscriptionGroup);
- final boolean vcnExists = mVcns.containsKey(subscriptionGroup);
-
- stopVcnLocked(subscriptionGroup);
-
- if (vcnExists) {
- // TODO(b/181789060): invoke asynchronously after Vcn notifies through
- // VcnCallback
- notifyAllPermissionedStatusCallbacksLocked(
- subscriptionGroup, VCN_STATUS_CODE_NOT_CONFIGURED);
- }
-
+ stopAndClearVcnConfigInternalLocked(subscriptionGroup);
writeConfigsToDiskLocked();
}
});
}
+ private void stopAndClearVcnConfigInternalLocked(@NonNull ParcelUuid subscriptionGroup) {
+ mConfigs.remove(subscriptionGroup);
+ final boolean vcnExists = mVcns.containsKey(subscriptionGroup);
+
+ stopVcnLocked(subscriptionGroup);
+
+ if (vcnExists) {
+ // TODO(b/181789060): invoke asynchronously after Vcn notifies through
+ // VcnCallback
+ notifyAllPermissionedStatusCallbacksLocked(
+ subscriptionGroup, VCN_STATUS_CODE_NOT_CONFIGURED);
+ }
+ }
+
+ private void garbageCollectAndWriteVcnConfigsLocked() {
+ final SubscriptionManager subMgr = mContext.getSystemService(SubscriptionManager.class);
+
+ boolean shouldWrite = false;
+
+ final Iterator<ParcelUuid> configsIterator = mConfigs.keySet().iterator();
+ while (configsIterator.hasNext()) {
+ final ParcelUuid subGrp = configsIterator.next();
+
+ final List<SubscriptionInfo> subscriptions = subMgr.getSubscriptionsInGroup(subGrp);
+ if (subscriptions == null || subscriptions.isEmpty()) {
+ // Trim subGrps with no more subscriptions; must have moved to another subGrp
+ configsIterator.remove();
+ shouldWrite = true;
+ }
+ }
+
+ if (shouldWrite) {
+ writeConfigsToDiskLocked();
+ }
+ }
+
/**
* Retrieves the list of subscription groups with configured VcnConfigs
*
- * <p>Limited to subscription groups for which the caller is carrier privileged.
+ * <p>Limited to subscription groups for which the caller had configured.
*
* <p>Implements the IVcnManagementService Binder interface.
*/
@@ -698,7 +794,8 @@
final List<ParcelUuid> result = new ArrayList<>();
synchronized (mLock) {
for (ParcelUuid subGrp : mConfigs.keySet()) {
- if (mLastSnapshot.packageHasPermissionsForSubscriptionGroup(subGrp, opPkgName)) {
+ if (mLastSnapshot.packageHasPermissionsForSubscriptionGroup(subGrp, opPkgName)
+ || isProvisioningPackageForConfig(subGrp, opPkgName)) {
result.add(subGrp);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 35f7e06..7cee203 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -15093,7 +15093,7 @@
@GuardedBy("this")
final boolean canGcNowLocked() {
for (BroadcastQueue q : mBroadcastQueues) {
- if (!q.mParallelBroadcasts.isEmpty() || !q.mDispatcher.isEmpty()) {
+ if (!q.mParallelBroadcasts.isEmpty() || !q.mDispatcher.isIdle()) {
return false;
}
}
diff --git a/services/core/java/com/android/server/am/AppBatteryTracker.java b/services/core/java/com/android/server/am/AppBatteryTracker.java
index 90201a0..8c42d4d 100644
--- a/services/core/java/com/android/server/am/AppBatteryTracker.java
+++ b/services/core/java/com/android/server/am/AppBatteryTracker.java
@@ -266,22 +266,16 @@
}
FrameworkStatsLog.write(FrameworkStatsLog.APP_BACKGROUND_RESTRICTIONS_INFO,
uid,
- FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__RESTRICTION_LEVEL__LEVEL_UNKNOWN,
- FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__THRESHOLD__THRESHOLD_UNKNOWN,
- FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__TRACKER__UNKNOWN_TRACKER,
+ AppBackgroundRestrictionsInfo.LEVEL_UNKNOWN, // RestrictionLevel
+ AppBackgroundRestrictionsInfo.THRESHOLD_UNKNOWN,
+ AppBackgroundRestrictionsInfo.UNKNOWN_TRACKER,
null /*byte[] fgs_tracker_info*/,
getBatteryTrackerInfoProtoLocked(uid) /*byte[] battery_tracker_info*/,
null /*byte[] broadcast_events_tracker_info*/,
null /*byte[] bind_service_events_tracker_info*/,
- FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__EXEMPTION_REASON__REASON_UNKNOWN,
- FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__OPT_LEVEL__UNKNOWN,
- FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__TARGET_SDK__SDK_UNKNOWN,
+ AppBackgroundRestrictionsInfo.REASON_UNKNOWN, // ExemptionReason
+ AppBackgroundRestrictionsInfo.UNKNOWN, // OptimizationLevel
+ AppBackgroundRestrictionsInfo.SDK_UNKNOWN, // TargetSdk
isLowRamDeviceStatic());
}
}
diff --git a/services/core/java/com/android/server/am/AppRestrictionController.java b/services/core/java/com/android/server/am/AppRestrictionController.java
index 635d86c..d70404f 100644
--- a/services/core/java/com/android/server/am/AppRestrictionController.java
+++ b/services/core/java/com/android/server/am/AppRestrictionController.java
@@ -116,6 +116,7 @@
import android.database.ContentObserver;
import android.graphics.drawable.Icon;
import android.net.Uri;
+import android.os.AppBackgroundRestrictionsInfo;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
@@ -123,7 +124,6 @@
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
-import android.os.PowerExemptionManager.ExemptionReason;
import android.os.PowerExemptionManager.ReasonCode;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -1095,6 +1095,14 @@
DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "restriction_exempted_packages";
/**
+ * Whether or not to show the notification for abusive apps, i.e. when the system
+ * detects it's draining significant amount of battery in the background.
+ * {@code true} - we'll show the prompt to user, {@code false} - we'll not show it.
+ */
+ static final String KEY_BG_PROMPT_ABUSIVE_APPS_TO_BG_RESTRICTED =
+ DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "prompt_abusive_apps_to_bg_restricted";
+
+ /**
* Default value to {@link #mBgAutoRestrictedBucket}.
*/
static final boolean DEFAULT_BG_AUTO_RESTRICTED_BUCKET_ON_BG_RESTRICTION = false;
@@ -1119,6 +1127,11 @@
*/
final boolean mDefaultBgPromptFgsWithNotiToBgRestricted;
+ /**
+ * Default value to {@link #mBgPromptAbusiveAppsToBgRestricted}.
+ */
+ final boolean mDefaultBgPromptAbusiveAppToBgRestricted;
+
volatile boolean mBgAutoRestrictedBucket;
volatile boolean mRestrictedBucketEnabled;
@@ -1144,10 +1157,17 @@
*/
volatile boolean mBgPromptFgsWithNotiOnLongRunning;
+ /**
+ * @see #KEY_BG_PROMPT_ABUSIVE_APPS_TO_BG_RESTRICTED.
+ */
+ volatile boolean mBgPromptAbusiveAppsToBgRestricted;
+
ConstantsObserver(Handler handler, Context context) {
super(handler);
mDefaultBgPromptFgsWithNotiToBgRestricted = context.getResources().getBoolean(
com.android.internal.R.bool.config_bg_prompt_fgs_with_noti_to_bg_restricted);
+ mDefaultBgPromptAbusiveAppToBgRestricted = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_bg_prompt_abusive_apps_to_bg_restricted);
}
@Override
@@ -1172,6 +1192,9 @@
case KEY_BG_PROMPT_FGS_WITH_NOTIFICATION_ON_LONG_RUNNING:
updateBgPromptFgsWithNotiOnLongRunning();
break;
+ case KEY_BG_PROMPT_ABUSIVE_APPS_TO_BG_RESTRICTED:
+ updateBgPromptAbusiveAppToBgRestricted();
+ break;
case KEY_BG_RESTRICTION_EXEMPTED_PACKAGES:
updateBgRestrictionExemptedPackages();
break;
@@ -1209,6 +1232,7 @@
updateBgLongFgsNotificationMinimalInterval();
updateBgPromptFgsWithNotiToBgRestricted();
updateBgPromptFgsWithNotiOnLongRunning();
+ updateBgPromptAbusiveAppToBgRestricted();
updateBgRestrictionExemptedPackages();
}
@@ -1251,6 +1275,13 @@
DEFAULT_BG_PROMPT_FGS_WITH_NOTIFICATION_ON_LONG_RUNNING);
}
+ private void updateBgPromptAbusiveAppToBgRestricted() {
+ mBgPromptAbusiveAppsToBgRestricted = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_BG_PROMPT_ABUSIVE_APPS_TO_BG_RESTRICTED,
+ mDefaultBgPromptAbusiveAppToBgRestricted);
+ }
+
private void updateBgRestrictionExemptedPackages() {
final String settings = DeviceConfig.getString(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -1290,6 +1321,10 @@
pw.print('=');
pw.println(mBgPromptFgsWithNotiToBgRestricted);
pw.print(prefix);
+ pw.print(KEY_BG_PROMPT_ABUSIVE_APPS_TO_BG_RESTRICTED);
+ pw.print('=');
+ pw.println(mBgPromptAbusiveAppsToBgRestricted);
+ pw.print(prefix);
pw.print(KEY_BG_RESTRICTION_EXEMPTED_PACKAGES);
pw.print('=');
pw.println(mBgRestrictionExemptedPackages.toString());
@@ -1881,76 +1916,59 @@
private int getRestrictionLevelStatsd(@RestrictionLevel int level) {
switch (level) {
case RESTRICTION_LEVEL_UNKNOWN:
- return FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__RESTRICTION_LEVEL__LEVEL_UNKNOWN;
+ return AppBackgroundRestrictionsInfo.LEVEL_UNKNOWN;
case RESTRICTION_LEVEL_UNRESTRICTED:
- return FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__RESTRICTION_LEVEL__LEVEL_UNRESTRICTED;
+ return AppBackgroundRestrictionsInfo.LEVEL_UNRESTRICTED;
case RESTRICTION_LEVEL_EXEMPTED:
- return FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__RESTRICTION_LEVEL__LEVEL_EXEMPTED;
+ return AppBackgroundRestrictionsInfo.LEVEL_EXEMPTED;
case RESTRICTION_LEVEL_ADAPTIVE_BUCKET:
- return FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__RESTRICTION_LEVEL__LEVEL_ADAPTIVE_BUCKET;
+ return AppBackgroundRestrictionsInfo.LEVEL_ADAPTIVE_BUCKET;
case RESTRICTION_LEVEL_RESTRICTED_BUCKET:
- return FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__RESTRICTION_LEVEL__LEVEL_RESTRICTED_BUCKET;
+ return AppBackgroundRestrictionsInfo.LEVEL_RESTRICTED_BUCKET;
case RESTRICTION_LEVEL_BACKGROUND_RESTRICTED:
- return FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__RESTRICTION_LEVEL__LEVEL_BACKGROUND_RESTRICTED;
+ return AppBackgroundRestrictionsInfo.LEVEL_BACKGROUND_RESTRICTED;
case RESTRICTION_LEVEL_HIBERNATION:
- return FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__RESTRICTION_LEVEL__LEVEL_HIBERNATION;
+ return AppBackgroundRestrictionsInfo.LEVEL_HIBERNATION;
default:
- return FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__RESTRICTION_LEVEL__LEVEL_UNKNOWN;
+ return AppBackgroundRestrictionsInfo.LEVEL_UNKNOWN;
}
}
private int getThresholdStatsd(int reason) {
switch (reason) {
case REASON_MAIN_FORCED_BY_SYSTEM:
- return FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__THRESHOLD__THRESHOLD_RESTRICTED;
+ return AppBackgroundRestrictionsInfo.THRESHOLD_RESTRICTED;
case REASON_MAIN_FORCED_BY_USER:
- return FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__THRESHOLD__THRESHOLD_USER;
+ return AppBackgroundRestrictionsInfo.THRESHOLD_USER;
default:
- return FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__THRESHOLD__THRESHOLD_UNKNOWN;
+ return AppBackgroundRestrictionsInfo.THRESHOLD_UNKNOWN;
}
}
private int getTrackerTypeStatsd(@TrackerType int type) {
switch (type) {
case TRACKER_TYPE_BATTERY:
- return FrameworkStatsLog.APP_BACKGROUND_RESTRICTIONS_INFO__TRACKER__BATTERY_TRACKER;
+ return AppBackgroundRestrictionsInfo.BATTERY_TRACKER;
case TRACKER_TYPE_BATTERY_EXEMPTION:
- return FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__TRACKER__BATTERY_EXEMPTION_TRACKER;
+ return AppBackgroundRestrictionsInfo.BATTERY_EXEMPTION_TRACKER;
case TRACKER_TYPE_FGS:
- return FrameworkStatsLog.APP_BACKGROUND_RESTRICTIONS_INFO__TRACKER__FGS_TRACKER;
+ return AppBackgroundRestrictionsInfo.FGS_TRACKER;
case TRACKER_TYPE_MEDIA_SESSION:
- return FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__TRACKER__MEDIA_SESSION_TRACKER;
+ return AppBackgroundRestrictionsInfo.MEDIA_SESSION_TRACKER;
case TRACKER_TYPE_PERMISSION:
- return FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__TRACKER__PERMISSION_TRACKER;
+ return AppBackgroundRestrictionsInfo.PERMISSION_TRACKER;
case TRACKER_TYPE_BROADCAST_EVENTS:
- return FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__TRACKER__BROADCAST_EVENTS_TRACKER;
+ return AppBackgroundRestrictionsInfo.BROADCAST_EVENTS_TRACKER;
case TRACKER_TYPE_BIND_SERVICE_EVENTS:
- return FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__TRACKER__BIND_SERVICE_EVENTS_TRACKER;
+ return AppBackgroundRestrictionsInfo.BIND_SERVICE_EVENTS_TRACKER;
default:
- return FrameworkStatsLog.APP_BACKGROUND_RESTRICTIONS_INFO__TRACKER__UNKNOWN_TRACKER;
+ return AppBackgroundRestrictionsInfo.UNKNOWN_TRACKER;
}
}
- private @ExemptionReason int getExemptionReasonStatsd(int uid, @RestrictionLevel int level) {
+ private int getExemptionReasonStatsd(int uid, @RestrictionLevel int level) {
if (level != RESTRICTION_LEVEL_EXEMPTED) {
- return FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__EXEMPTION_REASON__REASON_DENIED;
+ return AppBackgroundRestrictionsInfo.REASON_DENIED;
}
@ReasonCode final int reasonCode = getBackgroundRestrictionExemptionReason(uid);
@@ -1960,16 +1978,15 @@
private int getOptimizationLevelStatsd(@RestrictionLevel int level) {
switch (level) {
case RESTRICTION_LEVEL_UNKNOWN:
- return FrameworkStatsLog.APP_BACKGROUND_RESTRICTIONS_INFO__OPT_LEVEL__UNKNOWN;
+ return AppBackgroundRestrictionsInfo.UNKNOWN;
case RESTRICTION_LEVEL_UNRESTRICTED:
- return FrameworkStatsLog.APP_BACKGROUND_RESTRICTIONS_INFO__OPT_LEVEL__NOT_OPTIMIZED;
+ return AppBackgroundRestrictionsInfo.NOT_OPTIMIZED;
case RESTRICTION_LEVEL_ADAPTIVE_BUCKET:
- return FrameworkStatsLog.APP_BACKGROUND_RESTRICTIONS_INFO__OPT_LEVEL__OPTIMIZED;
+ return AppBackgroundRestrictionsInfo.OPTIMIZED;
case RESTRICTION_LEVEL_BACKGROUND_RESTRICTED:
- return FrameworkStatsLog
- .APP_BACKGROUND_RESTRICTIONS_INFO__OPT_LEVEL__BACKGROUND_RESTRICTED;
+ return AppBackgroundRestrictionsInfo.BACKGROUND_RESTRICTED;
default:
- return FrameworkStatsLog.APP_BACKGROUND_RESTRICTIONS_INFO__OPT_LEVEL__UNKNOWN;
+ return AppBackgroundRestrictionsInfo.UNKNOWN;
}
}
@@ -1977,26 +1994,26 @@
private int getTargetSdkStatsd(String packageName) {
final PackageManager pm = mInjector.getPackageManager();
if (pm == null) {
- return FrameworkStatsLog.APP_BACKGROUND_RESTRICTIONS_INFO__TARGET_SDK__SDK_UNKNOWN;
+ return AppBackgroundRestrictionsInfo.SDK_UNKNOWN;
}
try {
final PackageInfo pkg = pm.getPackageInfo(packageName, 0 /* flags */);
if (pkg == null || pkg.applicationInfo == null) {
- return FrameworkStatsLog.APP_BACKGROUND_RESTRICTIONS_INFO__TARGET_SDK__SDK_UNKNOWN;
+ return AppBackgroundRestrictionsInfo.SDK_UNKNOWN;
}
final int targetSdk = pkg.applicationInfo.targetSdkVersion;
if (targetSdk < Build.VERSION_CODES.S) {
- return FrameworkStatsLog.APP_BACKGROUND_RESTRICTIONS_INFO__TARGET_SDK__SDK_PRE_S;
+ return AppBackgroundRestrictionsInfo.SDK_PRE_S;
} else if (targetSdk < Build.VERSION_CODES.TIRAMISU) {
- return FrameworkStatsLog.APP_BACKGROUND_RESTRICTIONS_INFO__TARGET_SDK__SDK_S;
+ return AppBackgroundRestrictionsInfo.SDK_S;
} else if (targetSdk == Build.VERSION_CODES.TIRAMISU) {
- return FrameworkStatsLog.APP_BACKGROUND_RESTRICTIONS_INFO__TARGET_SDK__SDK_T;
+ return AppBackgroundRestrictionsInfo.SDK_T;
} else {
- return FrameworkStatsLog.APP_BACKGROUND_RESTRICTIONS_INFO__TARGET_SDK__SDK_UNKNOWN;
+ return AppBackgroundRestrictionsInfo.SDK_UNKNOWN;
}
} catch (PackageManager.NameNotFoundException ignored) {
}
- return FrameworkStatsLog.APP_BACKGROUND_RESTRICTIONS_INFO__TARGET_SDK__SDK_UNKNOWN;
+ return AppBackgroundRestrictionsInfo.SDK_UNKNOWN;
}
private void applyRestrictionLevel(String pkgName, int uid,
@@ -2296,9 +2313,16 @@
}
void postRequestBgRestrictedIfNecessary(String packageName, int uid) {
+ if (!mBgController.mConstantsObserver.mBgPromptAbusiveAppsToBgRestricted) {
+ if (DEBUG_BG_RESTRICTION_CONTROLLER) {
+ Slog.i(TAG, "Not requesting bg-restriction due to config");
+ }
+ return;
+ }
+
final Intent intent = new Intent(Settings.ACTION_VIEW_ADVANCED_POWER_USAGE_DETAIL);
intent.setData(Uri.fromParts(PACKAGE_SCHEME, packageName, null));
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
final PendingIntent pendingIntent = PendingIntent.getActivityAsUser(mContext, 0,
intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE, null,
@@ -2362,7 +2386,7 @@
} else {
final Intent intent = new Intent(Settings.ACTION_VIEW_ADVANCED_POWER_USAGE_DETAIL);
intent.setData(Uri.fromParts(PACKAGE_SCHEME, packageName, null));
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
pendingIntent = PendingIntent.getActivityAsUser(mContext, 0,
intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE,
null, UserHandle.of(UserHandle.getUserId(uid)));
diff --git a/services/core/java/com/android/server/am/BroadcastDispatcher.java b/services/core/java/com/android/server/am/BroadcastDispatcher.java
index 872531a..49477ad 100644
--- a/services/core/java/com/android/server/am/BroadcastDispatcher.java
+++ b/services/core/java/com/android/server/am/BroadcastDispatcher.java
@@ -512,12 +512,24 @@
*/
public boolean isEmpty() {
synchronized (mLock) {
+ return isIdle()
+ && getBootCompletedBroadcastsUidsSize(Intent.ACTION_LOCKED_BOOT_COMPLETED) == 0
+ && getBootCompletedBroadcastsUidsSize(Intent.ACTION_BOOT_COMPLETED) == 0;
+ }
+ }
+
+ /**
+ * Have less check than {@link #isEmpty()}.
+ * The dispatcher is considered as idle even with deferred LOCKED_BOOT_COMPLETED/BOOT_COMPLETED
+ * broadcasts because those can be deferred until the first time the uid's process is started.
+ * @return
+ */
+ public boolean isIdle() {
+ synchronized (mLock) {
return mCurrentBroadcast == null
&& mOrderedBroadcasts.isEmpty()
&& isDeferralsListEmpty(mDeferredBroadcasts)
- && isDeferralsListEmpty(mAlarmBroadcasts)
- && getBootCompletedBroadcastsUidsSize(Intent.ACTION_LOCKED_BOOT_COMPLETED) == 0
- && getBootCompletedBroadcastsUidsSize(Intent.ACTION_BOOT_COMPLETED) == 0;
+ && isDeferralsListEmpty(mAlarmBroadcasts);
}
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 8a7fece..dd7fb84 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -879,9 +879,9 @@
// Ensure that broadcasts are only sent to other apps if they are explicitly marked as
// exported, or are System level broadcasts
- if (!skip && !filter.exported && !Process.isCoreUid(r.callingUid)
- && filter.receiverList.uid != r.callingUid) {
-
+ if (!skip && !filter.exported && mService.checkComponentPermission(null, r.callingPid,
+ r.callingUid, filter.receiverList.uid, filter.exported)
+ != PackageManager.PERMISSION_GRANTED) {
Slog.w(TAG, "Exported Denial: sending "
+ r.intent.toString()
+ ", action: " + r.intent.getAction()
@@ -2218,7 +2218,7 @@
}
boolean isIdle() {
- return mParallelBroadcasts.isEmpty() && mDispatcher.isEmpty()
+ return mParallelBroadcasts.isEmpty() && mDispatcher.isIdle()
&& (mPendingBroadcast == null);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricStateCallback.java b/services/core/java/com/android/server/biometrics/sensors/BiometricStateCallback.java
new file mode 100644
index 0000000..1b24aa8
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricStateCallback.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2021 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.biometrics.sensors;
+
+import static android.hardware.biometrics.BiometricStateListener.STATE_AUTH_OTHER;
+import static android.hardware.biometrics.BiometricStateListener.STATE_BP_AUTH;
+import static android.hardware.biometrics.BiometricStateListener.STATE_ENROLLING;
+import static android.hardware.biometrics.BiometricStateListener.STATE_IDLE;
+import static android.hardware.biometrics.BiometricStateListener.STATE_KEYGUARD_AUTH;
+
+import android.annotation.NonNull;
+import android.hardware.biometrics.BiometricStateListener;
+import android.hardware.biometrics.IBiometricStateListener;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.biometrics.Utils;
+
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * A callback for receiving notifications about biometric sensor state changes.
+ */
+public class BiometricStateCallback implements ClientMonitorCallback {
+
+ private static final String TAG = "BiometricStateCallback";
+
+ @NonNull
+ private final CopyOnWriteArrayList<IBiometricStateListener>
+ mBiometricStateListeners = new CopyOnWriteArrayList<>();
+
+ private @BiometricStateListener.State int mBiometricState;
+
+ public BiometricStateCallback() {
+ mBiometricState = STATE_IDLE;
+ }
+
+ public int getBiometricState() {
+ return mBiometricState;
+ }
+
+ @Override
+ public void onClientStarted(@NonNull BaseClientMonitor client) {
+ final int previousBiometricState = mBiometricState;
+
+ if (client instanceof AuthenticationClient) {
+ final AuthenticationClient<?> authClient = (AuthenticationClient<?>) client;
+ if (authClient.isKeyguard()) {
+ mBiometricState = STATE_KEYGUARD_AUTH;
+ } else if (authClient.isBiometricPrompt()) {
+ mBiometricState = STATE_BP_AUTH;
+ } else {
+ mBiometricState = STATE_AUTH_OTHER;
+ }
+ } else if (client instanceof EnrollClient) {
+ mBiometricState = STATE_ENROLLING;
+ } else {
+ Slog.w(TAG, "Other authentication client: " + Utils.getClientName(client));
+ mBiometricState = STATE_IDLE;
+ }
+
+ Slog.d(TAG, "State updated from " + previousBiometricState + " to " + mBiometricState
+ + ", client " + client);
+ notifyBiometricStateListeners(mBiometricState);
+ }
+
+ @Override
+ public void onClientFinished(@NonNull BaseClientMonitor client, boolean success) {
+ mBiometricState = STATE_IDLE;
+ Slog.d(TAG, "Client finished, state updated to " + mBiometricState + ", client "
+ + client);
+
+ if (client instanceof EnrollmentModifier) {
+ EnrollmentModifier enrollmentModifier = (EnrollmentModifier) client;
+ final boolean enrollmentStateChanged = enrollmentModifier.hasEnrollmentStateChanged();
+ Slog.d(TAG, "Enrollment state changed: " + enrollmentStateChanged);
+ if (enrollmentStateChanged) {
+ notifyAllEnrollmentStateChanged(client.getTargetUserId(),
+ client.getSensorId(),
+ enrollmentModifier.hasEnrollments());
+ }
+ }
+
+ notifyBiometricStateListeners(mBiometricState);
+ }
+
+ private void notifyBiometricStateListeners(@BiometricStateListener.State int newState) {
+ for (IBiometricStateListener listener : mBiometricStateListeners) {
+ try {
+ listener.onStateChanged(newState);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception in biometric state change", e);
+ }
+ }
+ }
+
+ /**
+ * This should be invoked when:
+ * 1) Enrolled --> None-enrolled
+ * 2) None-enrolled --> enrolled
+ * 3) HAL becomes ready
+ * 4) Listener is registered
+ */
+ public void notifyAllEnrollmentStateChanged(int userId, int sensorId,
+ boolean hasEnrollments) {
+ for (IBiometricStateListener listener : mBiometricStateListeners) {
+ notifyEnrollmentStateChanged(listener, userId, sensorId, hasEnrollments);
+ }
+ }
+
+ /**
+ * Notifies the listener of enrollment state changes.
+ */
+ public void notifyEnrollmentStateChanged(@NonNull IBiometricStateListener listener,
+ int userId, int sensorId, boolean hasEnrollments) {
+ try {
+ listener.onEnrollmentsChanged(userId, sensorId, hasEnrollments);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ }
+
+ /**
+ * Enables clients to register a BiometricStateListener. For example, this is used to forward
+ * fingerprint sensor state changes to SideFpsEventHandler.
+ *
+ * @param listener
+ */
+ public void registerBiometricStateListener(@NonNull IBiometricStateListener listener) {
+ mBiometricStateListeners.add(listener);
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 5727ffc..97efc78 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -42,6 +42,7 @@
import android.hardware.biometrics.IBiometricSensorReceiver;
import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
+import android.hardware.biometrics.IBiometricStateListener;
import android.hardware.biometrics.IInvalidationCallback;
import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.ITestSessionCallback;
@@ -55,7 +56,6 @@
import android.hardware.fingerprint.IFingerprintClientActiveCallback;
import android.hardware.fingerprint.IFingerprintService;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
-import android.hardware.fingerprint.IFingerprintStateListener;
import android.hardware.fingerprint.ISidefpsController;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.Binder;
@@ -84,6 +84,7 @@
import com.android.server.SystemService;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.log.BiometricContext;
+import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.LockoutTracker;
@@ -114,7 +115,7 @@
private final LockPatternUtils mLockPatternUtils;
private final FingerprintServiceWrapper mServiceWrapper;
@NonNull private final List<ServiceProvider> mServiceProviders;
- @NonNull private final FingerprintStateCallback mFingerprintStateCallback;
+ @NonNull private final BiometricStateCallback mBiometricStateCallback;
@NonNull private final Handler mHandler;
@GuardedBy("mLock")
@@ -125,20 +126,20 @@
@NonNull private final List<FingerprintSensorPropertiesInternal> mSensorProps;
/**
- * Registers FingerprintStateListener in list stored by FingerprintService
- * @param listener new FingerprintStateListener being added
+ * Registers BiometricStateListener in list stored by FingerprintService
+ * @param listener new BiometricStateListener being added
*/
- public void registerFingerprintStateListener(@NonNull IFingerprintStateListener listener) {
- mFingerprintStateCallback.registerFingerprintStateListener(listener);
+ public void registerBiometricStateListener(@NonNull IBiometricStateListener listener) {
+ mBiometricStateCallback.registerBiometricStateListener(listener);
broadcastCurrentEnrollmentState(listener);
}
/**
* @param listener if non-null, notifies only this listener. if null, notifies all listeners
- * in {@link FingerprintStateCallback}. This is slightly ugly, but reduces
+ * in {@link BiometricStateCallback}. This is slightly ugly, but reduces
* redundant code.
*/
- private void broadcastCurrentEnrollmentState(@Nullable IFingerprintStateListener listener) {
+ private void broadcastCurrentEnrollmentState(@Nullable IBiometricStateListener listener) {
final UserManager um = UserManager.get(getContext());
synchronized (mLock) {
// Update the new listener with current state of all sensors
@@ -151,10 +152,10 @@
// Defer this work and allow the loop to release the lock sooner
mHandler.post(() -> {
if (listener != null) {
- mFingerprintStateCallback.notifyFingerprintEnrollmentStateChanged(
+ mBiometricStateCallback.notifyEnrollmentStateChanged(
listener, userInfo.id, prop.sensorId, enrolled);
} else {
- mFingerprintStateCallback.notifyAllFingerprintEnrollmentStateChanged(
+ mBiometricStateCallback.notifyAllEnrollmentStateChanged(
userInfo.id, prop.sensorId, enrolled);
}
});
@@ -651,7 +652,7 @@
pw.println("Dumping for sensorId: " + props.sensorId
+ ", provider: " + provider.getClass().getSimpleName());
pw.println("Fps state: "
- + mFingerprintStateCallback.getFingerprintState());
+ + mBiometricStateCallback.getBiometricState());
provider.dumpInternal(props.sensorId, pw);
pw.println();
}
@@ -847,12 +848,12 @@
Fingerprint21UdfpsMock.CONFIG_ENABLE_TEST_UDFPS, 0 /* default */,
UserHandle.USER_CURRENT) != 0) {
fingerprint21 = Fingerprint21UdfpsMock.newInstance(getContext(),
- mFingerprintStateCallback, hidlSensor,
+ mBiometricStateCallback, hidlSensor,
mLockoutResetDispatcher, mGestureAvailabilityDispatcher,
BiometricContext.getInstance(getContext()));
} else {
fingerprint21 = Fingerprint21.newInstance(getContext(),
- mFingerprintStateCallback, hidlSensor, mHandler,
+ mBiometricStateCallback, hidlSensor, mHandler,
mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
}
mServiceProviders.add(fingerprint21);
@@ -875,7 +876,7 @@
try {
final SensorProps[] props = fp.getSensorProps();
final FingerprintProvider provider =
- new FingerprintProvider(getContext(), mFingerprintStateCallback, props,
+ new FingerprintProvider(getContext(), mBiometricStateCallback, props,
instance, mLockoutResetDispatcher,
mGestureAvailabilityDispatcher,
BiometricContext.getInstance(getContext()));
@@ -1015,8 +1016,8 @@
}
@Override
- public void registerFingerprintStateListener(@NonNull IFingerprintStateListener listener) {
- FingerprintService.this.registerFingerprintStateListener(listener);
+ public void registerBiometricStateListener(@NonNull IBiometricStateListener listener) {
+ FingerprintService.this.registerBiometricStateListener(listener);
}
}
@@ -1028,7 +1029,7 @@
mLockoutResetDispatcher = new LockoutResetDispatcher(context);
mLockPatternUtils = new LockPatternUtils(context);
mServiceProviders = new ArrayList<>();
- mFingerprintStateCallback = new FingerprintStateCallback();
+ mBiometricStateCallback = new BiometricStateCallback();
mAuthenticatorsRegisteredCallbacks = new RemoteCallbackList<>();
mSensorProps = new ArrayList<>();
mHandler = new Handler(Looper.getMainLooper());
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallback.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallback.java
deleted file mode 100644
index 04fd534..0000000
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallback.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2021 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.biometrics.sensors.fingerprint;
-
-import static android.hardware.fingerprint.FingerprintStateListener.STATE_AUTH_OTHER;
-import static android.hardware.fingerprint.FingerprintStateListener.STATE_BP_AUTH;
-import static android.hardware.fingerprint.FingerprintStateListener.STATE_ENROLLING;
-import static android.hardware.fingerprint.FingerprintStateListener.STATE_IDLE;
-import static android.hardware.fingerprint.FingerprintStateListener.STATE_KEYGUARD_AUTH;
-
-import android.annotation.NonNull;
-import android.hardware.fingerprint.FingerprintStateListener;
-import android.hardware.fingerprint.IFingerprintStateListener;
-import android.os.RemoteException;
-import android.util.Slog;
-
-import com.android.server.biometrics.Utils;
-import com.android.server.biometrics.sensors.AuthenticationClient;
-import com.android.server.biometrics.sensors.BaseClientMonitor;
-import com.android.server.biometrics.sensors.ClientMonitorCallback;
-import com.android.server.biometrics.sensors.EnrollClient;
-import com.android.server.biometrics.sensors.EnrollmentModifier;
-
-import java.util.concurrent.CopyOnWriteArrayList;
-
-/**
- * A callback for receiving notifications about changes in fingerprint state.
- */
-public class FingerprintStateCallback implements ClientMonitorCallback {
-
- @NonNull private final CopyOnWriteArrayList<IFingerprintStateListener>
- mFingerprintStateListeners = new CopyOnWriteArrayList<>();
-
- private @FingerprintStateListener.State int mFingerprintState;
-
- public FingerprintStateCallback() {
- mFingerprintState = STATE_IDLE;
- }
-
- public int getFingerprintState() {
- return mFingerprintState;
- }
-
- @Override
- public void onClientStarted(@NonNull BaseClientMonitor client) {
- final int previousFingerprintState = mFingerprintState;
-
- if (client instanceof AuthenticationClient) {
- final AuthenticationClient<?> authClient = (AuthenticationClient<?>) client;
- if (authClient.isKeyguard()) {
- mFingerprintState = STATE_KEYGUARD_AUTH;
- } else if (authClient.isBiometricPrompt()) {
- mFingerprintState = STATE_BP_AUTH;
- } else {
- mFingerprintState = STATE_AUTH_OTHER;
- }
- } else if (client instanceof EnrollClient) {
- mFingerprintState = STATE_ENROLLING;
- } else {
- Slog.w(FingerprintService.TAG,
- "Other authentication client: " + Utils.getClientName(client));
- mFingerprintState = STATE_IDLE;
- }
-
- Slog.d(FingerprintService.TAG, "Fps state updated from " + previousFingerprintState
- + " to " + mFingerprintState + ", client " + client);
- notifyFingerprintStateListeners(mFingerprintState);
- }
-
- @Override
- public void onClientFinished(@NonNull BaseClientMonitor client, boolean success) {
- mFingerprintState = STATE_IDLE;
- Slog.d(FingerprintService.TAG,
- "Client finished, fps state updated to " + mFingerprintState + ", client "
- + client);
-
- if (client instanceof EnrollmentModifier) {
- EnrollmentModifier enrollmentModifier = (EnrollmentModifier) client;
- final boolean enrollmentStateChanged = enrollmentModifier.hasEnrollmentStateChanged();
- Slog.d(FingerprintService.TAG, "Enrollment state changed: " + enrollmentStateChanged);
- if (enrollmentStateChanged) {
- notifyAllFingerprintEnrollmentStateChanged(client.getTargetUserId(),
- client.getSensorId(),
- enrollmentModifier.hasEnrollments());
- }
- }
-
- notifyFingerprintStateListeners(mFingerprintState);
- }
-
- private void notifyFingerprintStateListeners(@FingerprintStateListener.State int newState) {
- for (IFingerprintStateListener listener : mFingerprintStateListeners) {
- try {
- listener.onStateChanged(newState);
- } catch (RemoteException e) {
- Slog.e(FingerprintService.TAG, "Remote exception in fingerprint state change", e);
- }
- }
- }
-
- /**
- * This should be invoked when:
- * 1) Enrolled --> None-enrolled
- * 2) None-enrolled --> enrolled
- * 3) HAL becomes ready
- * 4) Listener is registered
- */
- void notifyAllFingerprintEnrollmentStateChanged(int userId, int sensorId,
- boolean hasEnrollments) {
- for (IFingerprintStateListener listener : mFingerprintStateListeners) {
- notifyFingerprintEnrollmentStateChanged(listener, userId, sensorId, hasEnrollments);
- }
- }
-
- /**
- * Notifies the listener of enrollment state changes.
- */
- void notifyFingerprintEnrollmentStateChanged(@NonNull IFingerprintStateListener listener,
- int userId, int sensorId, boolean hasEnrollments) {
- try {
- listener.onEnrollmentsChanged(userId, sensorId, hasEnrollments);
- } catch (RemoteException e) {
- Slog.e(FingerprintService.TAG, "Remote exception", e);
- }
- }
-
- /**
- * Enables clients to register a FingerprintStateListener. Used by FingerprintService to forward
- * updates in fingerprint sensor state to the SideFpNsEventHandler
- *
- * @param listener
- */
- public void registerFingerprintStateListener(@NonNull IFingerprintStateListener listener) {
- mFingerprintStateListeners.add(listener);
- }
-}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
index 0528cd4..ba7202f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
@@ -32,8 +32,8 @@
import com.android.server.biometrics.HardwareAuthTokenUtils;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.BaseClientMonitor;
+import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
-import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback;
import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
import java.util.HashSet;
@@ -52,7 +52,7 @@
@NonNull private final Context mContext;
private final int mSensorId;
@NonNull private final ITestSessionCallback mCallback;
- @NonNull private final FingerprintStateCallback mFingerprintStateCallback;
+ @NonNull private final BiometricStateCallback mBiometricStateCallback;
@NonNull private final FingerprintProvider mProvider;
@NonNull private final Sensor mSensor;
@NonNull private final Set<Integer> mEnrollmentIds;
@@ -118,13 +118,13 @@
BiometricTestSessionImpl(@NonNull Context context, int sensorId,
@NonNull ITestSessionCallback callback,
- @NonNull FingerprintStateCallback fingerprintStateCallback,
+ @NonNull BiometricStateCallback biometricStateCallback,
@NonNull FingerprintProvider provider,
@NonNull Sensor sensor) {
mContext = context;
mSensorId = sensorId;
mCallback = callback;
- mFingerprintStateCallback = fingerprintStateCallback;
+ mBiometricStateCallback = biometricStateCallback;
mProvider = provider;
mSensor = sensor;
mEnrollmentIds = new HashSet<>();
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index 1fac8a8..7d5b77c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -58,13 +58,13 @@
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.BaseClientMonitor;
+import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.ClientMonitorCompositeCallback;
import com.android.server.biometrics.sensors.InvalidationRequesterClient;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.PerformanceTracker;
-import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback;
import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
import com.android.server.biometrics.sensors.fingerprint.ServiceProvider;
@@ -91,7 +91,7 @@
private boolean mTestHalEnabled;
@NonNull private final Context mContext;
- @NonNull private final FingerprintStateCallback mFingerprintStateCallback;
+ @NonNull private final BiometricStateCallback mBiometricStateCallback;
@NonNull private final String mHalInstanceName;
@NonNull @VisibleForTesting
final SparseArray<Sensor> mSensors; // Map of sensors that this HAL supports
@@ -141,13 +141,13 @@
}
public FingerprintProvider(@NonNull Context context,
- @NonNull FingerprintStateCallback fingerprintStateCallback,
+ @NonNull BiometricStateCallback biometricStateCallback,
@NonNull SensorProps[] props, @NonNull String halInstanceName,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
@NonNull BiometricContext biometricContext) {
mContext = context;
- mFingerprintStateCallback = fingerprintStateCallback;
+ mBiometricStateCallback = biometricStateCallback;
mHalInstanceName = halInstanceName;
mSensors = new SparseArray<>();
mHandler = new Handler(Looper.getMainLooper());
@@ -389,13 +389,13 @@
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
- mFingerprintStateCallback.onClientStarted(clientMonitor);
+ mBiometricStateCallback.onClientStarted(clientMonitor);
}
@Override
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
boolean success) {
- mFingerprintStateCallback.onClientFinished(clientMonitor, success);
+ mBiometricStateCallback.onClientFinished(clientMonitor, success);
if (success) {
scheduleLoadAuthenticatorIdsForUser(sensorId, userId);
scheduleInvalidationRequest(sensorId, userId);
@@ -425,7 +425,7 @@
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient),
mBiometricContext,
mUdfpsOverlayController, isStrongBiometric);
- scheduleForSensor(sensorId, client, mFingerprintStateCallback);
+ scheduleForSensor(sensorId, client, mBiometricStateCallback);
});
return id;
@@ -447,7 +447,7 @@
mTaskStackListener, mSensors.get(sensorId).getLockoutCache(),
mUdfpsOverlayController, mSidefpsController, allowBackgroundAuthentication,
mSensors.get(sensorId).getSensorProperties());
- scheduleForSensor(sensorId, client, mFingerprintStateCallback);
+ scheduleForSensor(sensorId, client, mBiometricStateCallback);
});
}
@@ -509,7 +509,7 @@
BiometricsProtoEnums.CLIENT_UNKNOWN),
mBiometricContext,
mSensors.get(sensorId).getAuthenticatorIds());
- scheduleForSensor(sensorId, client, mFingerprintStateCallback);
+ scheduleForSensor(sensorId, client, mBiometricStateCallback);
});
}
@@ -528,7 +528,7 @@
enrolledList, FingerprintUtils.getInstance(sensorId),
mSensors.get(sensorId).getAuthenticatorIds());
scheduleForSensor(sensorId, client, new ClientMonitorCompositeCallback(callback,
- mFingerprintStateCallback));
+ mBiometricStateCallback));
});
}
@@ -680,7 +680,7 @@
@Override
public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
@NonNull String opPackageName) {
- return mSensors.get(sensorId).createTestSession(callback, mFingerprintStateCallback);
+ return mSensors.get(sensorId).createTestSession(callback, mBiometricStateCallback);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
index 024d611..1dcf4e9 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
@@ -55,6 +55,7 @@
import com.android.server.biometrics.sensors.AuthenticationConsumer;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricScheduler;
+import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.EnumerateConsumer;
import com.android.server.biometrics.sensors.ErrorConsumer;
import com.android.server.biometrics.sensors.LockoutCache;
@@ -64,7 +65,6 @@
import com.android.server.biometrics.sensors.StartUserClient;
import com.android.server.biometrics.sensors.StopUserClient;
import com.android.server.biometrics.sensors.UserAwareBiometricScheduler;
-import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback;
import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
@@ -527,9 +527,9 @@
}
@NonNull ITestSession createTestSession(@NonNull ITestSessionCallback callback,
- @NonNull FingerprintStateCallback fingerprintStateCallback) {
+ @NonNull BiometricStateCallback biometricStateCallback) {
return new BiometricTestSessionImpl(mContext, mSensorProperties.sensorId, callback,
- fingerprintStateCallback, mProvider, this);
+ biometricStateCallback, mProvider, this);
}
@NonNull BiometricScheduler getScheduler() {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
index 033855f..a58bb89 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
@@ -31,8 +31,8 @@
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.BaseClientMonitor;
+import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
-import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback;
import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
import java.util.ArrayList;
@@ -53,7 +53,7 @@
@NonNull private final Context mContext;
private final int mSensorId;
@NonNull private final ITestSessionCallback mCallback;
- @NonNull private final FingerprintStateCallback mFingerprintStateCallback;
+ @NonNull private final BiometricStateCallback mBiometricStateCallback;
@NonNull private final Fingerprint21 mFingerprint21;
@NonNull private final Fingerprint21.HalResultController mHalResultController;
@NonNull private final Set<Integer> mEnrollmentIds;
@@ -119,14 +119,14 @@
BiometricTestSessionImpl(@NonNull Context context, int sensorId,
@NonNull ITestSessionCallback callback,
- @NonNull FingerprintStateCallback fingerprintStateCallback,
+ @NonNull BiometricStateCallback biometricStateCallback,
@NonNull Fingerprint21 fingerprint21,
@NonNull Fingerprint21.HalResultController halResultController) {
mContext = context;
mSensorId = sensorId;
mCallback = callback;
mFingerprint21 = fingerprint21;
- mFingerprintStateCallback = fingerprintStateCallback;
+ mBiometricStateCallback = biometricStateCallback;
mHalResultController = halResultController;
mEnrollmentIds = new HashSet<>();
mRandom = new Random();
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index 1d2a365..52dbe24 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -64,6 +64,7 @@
import com.android.server.biometrics.sensors.AuthenticationConsumer;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricScheduler;
+import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.ClientMonitorCompositeCallback;
@@ -73,7 +74,6 @@
import com.android.server.biometrics.sensors.LockoutTracker;
import com.android.server.biometrics.sensors.PerformanceTracker;
import com.android.server.biometrics.sensors.RemovalConsumer;
-import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback;
import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
import com.android.server.biometrics.sensors.fingerprint.ServiceProvider;
@@ -105,7 +105,7 @@
private boolean mTestHalEnabled;
final Context mContext;
- @NonNull private final FingerprintStateCallback mFingerprintStateCallback;
+ @NonNull private final BiometricStateCallback mBiometricStateCallback;
private final ActivityTaskManager mActivityTaskManager;
@NonNull private final FingerprintSensorPropertiesInternal mSensorProperties;
private final BiometricScheduler mScheduler;
@@ -323,7 +323,7 @@
@VisibleForTesting
Fingerprint21(@NonNull Context context,
- @NonNull FingerprintStateCallback fingerprintStateCallback,
+ @NonNull BiometricStateCallback biometricStateCallback,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull BiometricScheduler scheduler,
@NonNull Handler handler,
@@ -331,7 +331,7 @@
@NonNull HalResultController controller,
@NonNull BiometricContext biometricContext) {
mContext = context;
- mFingerprintStateCallback = fingerprintStateCallback;
+ mBiometricStateCallback = biometricStateCallback;
mBiometricContext = biometricContext;
mSensorProperties = sensorProps;
@@ -362,7 +362,7 @@
}
public static Fingerprint21 newInstance(@NonNull Context context,
- @NonNull FingerprintStateCallback fingerprintStateCallback,
+ @NonNull BiometricStateCallback biometricStateCallback,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull Handler handler,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@@ -373,7 +373,7 @@
gestureAvailabilityDispatcher);
final HalResultController controller = new HalResultController(sensorProps.sensorId,
context, handler, scheduler);
- return new Fingerprint21(context, fingerprintStateCallback, sensorProps, scheduler, handler,
+ return new Fingerprint21(context, biometricStateCallback, sensorProps, scheduler, handler,
lockoutResetDispatcher, controller, BiometricContext.getInstance(context));
}
@@ -604,13 +604,13 @@
mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
- mFingerprintStateCallback.onClientStarted(clientMonitor);
+ mBiometricStateCallback.onClientStarted(clientMonitor);
}
@Override
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
boolean success) {
- mFingerprintStateCallback.onClientFinished(clientMonitor, success);
+ mBiometricStateCallback.onClientFinished(clientMonitor, success);
if (success) {
// Update authenticatorIds
scheduleUpdateActiveUserWithoutHandler(clientMonitor.getTargetUserId(),
@@ -642,7 +642,7 @@
createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient),
mBiometricContext, mUdfpsOverlayController,
isStrongBiometric);
- mScheduler.scheduleClientMonitor(client, mFingerprintStateCallback);
+ mScheduler.scheduleClientMonitor(client, mBiometricStateCallback);
});
return id;
@@ -666,7 +666,7 @@
mTaskStackListener, mLockoutTracker,
mUdfpsOverlayController, mSidefpsController,
allowBackgroundAuthentication, mSensorProperties);
- mScheduler.scheduleClientMonitor(client, mFingerprintStateCallback);
+ mScheduler.scheduleClientMonitor(client, mBiometricStateCallback);
});
}
@@ -708,7 +708,7 @@
createLogger(BiometricsProtoEnums.ACTION_REMOVE,
BiometricsProtoEnums.CLIENT_UNKNOWN),
mBiometricContext, mAuthenticatorIds);
- mScheduler.scheduleClientMonitor(client, mFingerprintStateCallback);
+ mScheduler.scheduleClientMonitor(client, mBiometricStateCallback);
});
}
@@ -728,7 +728,7 @@
createLogger(BiometricsProtoEnums.ACTION_REMOVE,
BiometricsProtoEnums.CLIENT_UNKNOWN),
mBiometricContext, mAuthenticatorIds);
- mScheduler.scheduleClientMonitor(client, mFingerprintStateCallback);
+ mScheduler.scheduleClientMonitor(client, mBiometricStateCallback);
});
}
@@ -754,7 +754,7 @@
public void scheduleInternalCleanup(int sensorId, int userId,
@Nullable ClientMonitorCallback callback) {
scheduleInternalCleanup(userId, new ClientMonitorCompositeCallback(callback,
- mFingerprintStateCallback));
+ mBiometricStateCallback));
}
private BiometricLogger createLogger(int statsAction, int statsClient) {
@@ -967,6 +967,6 @@
public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
@NonNull String opPackageName) {
return new BiometricTestSessionImpl(mContext, mSensorProperties.sensorId, callback,
- mFingerprintStateCallback, this, mHalResultController);
+ mBiometricStateCallback, this, mHalResultController);
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
index a4e343e..485a674 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
@@ -41,9 +41,9 @@
import com.android.server.biometrics.sensors.AuthenticationConsumer;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricScheduler;
+import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
-import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
import java.util.ArrayList;
@@ -245,7 +245,7 @@
}
public static Fingerprint21UdfpsMock newInstance(@NonNull Context context,
- @NonNull FingerprintStateCallback fingerprintStateCallback,
+ @NonNull BiometricStateCallback biometricStateCallback,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
@@ -257,7 +257,7 @@
new TestableBiometricScheduler(TAG, handler, gestureAvailabilityDispatcher);
final MockHalResultController controller =
new MockHalResultController(sensorProps.sensorId, context, handler, scheduler);
- return new Fingerprint21UdfpsMock(context, fingerprintStateCallback, sensorProps, scheduler,
+ return new Fingerprint21UdfpsMock(context, biometricStateCallback, sensorProps, scheduler,
handler, lockoutResetDispatcher, controller, biometricContext);
}
@@ -382,14 +382,14 @@
}
private Fingerprint21UdfpsMock(@NonNull Context context,
- @NonNull FingerprintStateCallback fingerprintStateCallback,
+ @NonNull BiometricStateCallback biometricStateCallback,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull TestableBiometricScheduler scheduler,
@NonNull Handler handler,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull MockHalResultController controller,
@NonNull BiometricContext biometricContext) {
- super(context, fingerprintStateCallback, sensorProps, scheduler, handler,
+ super(context, biometricStateCallback, sensorProps, scheduler, handler,
lockoutResetDispatcher, controller, biometricContext);
mScheduler = scheduler;
mScheduler.init(this);
diff --git a/services/core/java/com/android/server/location/gnss/hal/GnssNative.java b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
index af87677..1fa56bc 100644
--- a/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
+++ b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java
@@ -47,6 +47,7 @@
import java.lang.annotation.Target;
import java.util.List;
import java.util.Objects;
+import java.util.concurrent.TimeUnit;
/**
* Entry point for most GNSS HAL commands and callbacks.
@@ -1271,7 +1272,8 @@
@NativeEntryPoint
boolean isInEmergencySession() {
return Binder.withCleanCallingIdentity(
- () -> mEmergencyHelper.isInEmergency(mConfiguration.getEsExtensionSec()));
+ () -> mEmergencyHelper.isInEmergency(
+ TimeUnit.SECONDS.toMillis(mConfiguration.getEsExtensionSec())));
}
/**
diff --git a/services/core/java/com/android/server/logcat/LogcatManagerService.java b/services/core/java/com/android/server/logcat/LogcatManagerService.java
index f856193..5dccd07 100644
--- a/services/core/java/com/android/server/logcat/LogcatManagerService.java
+++ b/services/core/java/com/android/server/logcat/LogcatManagerService.java
@@ -208,7 +208,7 @@
.getUidProcessState(mUid);
// If the process is foreground and we can retrieve the package name, show a dialog
// for user consent
- if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
+ if (procState == ActivityManager.PROCESS_STATE_TOP) {
String packageName = getPackageName(mUid, mGid, mPid, mFd);
if (packageName != null) {
final Intent mIntent = createIntent(packageName, mUid, mGid, mPid, mFd);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 8ed145c..3eee572 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -5827,7 +5827,7 @@
// Add summary
final ApplicationInfo appInfo =
adjustedSbn.getNotification().extras.getParcelable(
- Notification.EXTRA_BUILDER_APPLICATION_INFO);
+ Notification.EXTRA_BUILDER_APPLICATION_INFO, ApplicationInfo.class);
final Bundle extras = new Bundle();
extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
final String channelId = notificationRecord.getChannel().getId();
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 849f530..349174d 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -207,6 +207,9 @@
STORAGE_PERMISSIONS.add(Manifest.permission.READ_EXTERNAL_STORAGE);
STORAGE_PERMISSIONS.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
STORAGE_PERMISSIONS.add(Manifest.permission.ACCESS_MEDIA_LOCATION);
+ STORAGE_PERMISSIONS.add(Manifest.permission.READ_MEDIA_AUDIO);
+ STORAGE_PERMISSIONS.add(Manifest.permission.READ_MEDIA_VIDEO);
+ STORAGE_PERMISSIONS.add(Manifest.permission.READ_MEDIA_IMAGES);
}
private static final Set<String> NEARBY_DEVICES_PERMISSIONS = new ArraySet<>();
diff --git a/services/core/java/com/android/server/pm/resolution/ComponentResolver.java b/services/core/java/com/android/server/pm/resolution/ComponentResolver.java
index 9aa53f1..7baec62 100644
--- a/services/core/java/com/android/server/pm/resolution/ComponentResolver.java
+++ b/services/core/java/com/android/server/pm/resolution/ComponentResolver.java
@@ -79,7 +79,8 @@
import java.util.function.Function;
/** Resolves all Android component types [activities, services, providers and receivers]. */
-public class ComponentResolver extends ComponentResolverLocked implements Snappable {
+public class ComponentResolver extends ComponentResolverLocked implements
+ Snappable<ComponentResolverApi> {
private static final boolean DEBUG = false;
private static final String TAG = "PackageManager";
private static final boolean DEBUG_FILTERS = false;
@@ -166,11 +167,13 @@
mProvidersByAuthority = new ArrayMap<>();
mDeferProtectedFilters = true;
- mSnapshot = new SnapshotCache<ComponentResolverApi>(this, this) {
+ mSnapshot = new SnapshotCache<>(this, this) {
@Override
public ComponentResolverApi createSnapshot() {
- return new ComponentResolverSnapshot(ComponentResolver.this,
- userNeedsBadgingCache);
+ synchronized (mLock) {
+ return new ComponentResolverSnapshot(ComponentResolver.this,
+ userNeedsBadgingCache);
+ }
}};
}
diff --git a/services/core/java/com/android/server/policy/SideFpsEventHandler.java b/services/core/java/com/android/server/policy/SideFpsEventHandler.java
index f368698..41d0272 100644
--- a/services/core/java/com/android/server/policy/SideFpsEventHandler.java
+++ b/services/core/java/com/android/server/policy/SideFpsEventHandler.java
@@ -16,9 +16,9 @@
package com.android.server.policy;
-import static android.hardware.fingerprint.FingerprintStateListener.STATE_BP_AUTH;
-import static android.hardware.fingerprint.FingerprintStateListener.STATE_ENROLLING;
-import static android.hardware.fingerprint.FingerprintStateListener.STATE_IDLE;
+import static android.hardware.biometrics.BiometricStateListener.STATE_BP_AUTH;
+import static android.hardware.biometrics.BiometricStateListener.STATE_ENROLLING;
+import static android.hardware.biometrics.BiometricStateListener.STATE_IDLE;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -30,9 +30,9 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.hardware.biometrics.BiometricStateListener;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
-import android.hardware.fingerprint.FingerprintStateListener;
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
import android.os.Handler;
import android.os.PowerManager;
@@ -67,7 +67,7 @@
}
};
- private @FingerprintStateListener.State int mFingerprintState;
+ private @BiometricStateListener.State int mBiometricState;
SideFpsEventHandler(Context context, Handler handler, PowerManager powerManager) {
this(context, handler, powerManager, () -> new AlertDialog.Builder(context));
@@ -80,7 +80,7 @@
mHandler = handler;
mPowerManager = powerManager;
mDialogSupplier = dialogSupplier;
- mFingerprintState = STATE_IDLE;
+ mBiometricState = STATE_IDLE;
mSideFpsEventHandlerReady = new AtomicBoolean(false);
// ensure dialog is dismissed if screen goes off for unrelated reasons
@@ -108,7 +108,7 @@
return false;
}
- switch (mFingerprintState) {
+ switch (mBiometricState) {
case STATE_ENROLLING:
case STATE_BP_AUTH:
mHandler.post(() -> {
@@ -116,7 +116,7 @@
mDialog.dismiss();
}
mDialog = showConfirmDialog(mDialogSupplier.get(),
- mPowerManager, eventTime, mFingerprintState, mDialogDismissListener);
+ mPowerManager, eventTime, mBiometricState, mDialogDismissListener);
});
return true;
default:
@@ -127,9 +127,9 @@
@NonNull
private static Dialog showConfirmDialog(@NonNull AlertDialog.Builder dialogBuilder,
@NonNull PowerManager powerManager, long eventTime,
- @FingerprintStateListener.State int fingerprintState,
+ @BiometricStateListener.State int biometricState,
@NonNull DialogInterface.OnDismissListener dismissListener) {
- final boolean enrolling = fingerprintState == STATE_ENROLLING;
+ final boolean enrolling = biometricState == STATE_ENROLLING;
final int title = enrolling ? R.string.fp_power_button_enrollment_title
: R.string.fp_power_button_bp_title;
final int message = enrolling ? R.string.fp_power_button_enrollment_message
@@ -165,8 +165,8 @@
/**
* Awaits notification from PhoneWindowManager that fingerprint service is ready
* to send updates about power button fps sensor state. Then configures a
- * FingerprintStateListener to receive and record updates to fps state, and
- * registers the FingerprintStateListener in FingerprintManager.
+ * BiometricStateListener to receive and record updates to fps state, and
+ * registers the BiometricStateListener in FingerprintManager.
*/
public void onFingerprintSensorReady() {
final PackageManager pm = mContext.getPackageManager();
@@ -182,13 +182,14 @@
public void onAllAuthenticatorsRegistered(
List<FingerprintSensorPropertiesInternal> sensors) {
if (fingerprintManager.isPowerbuttonFps()) {
- fingerprintManager.registerFingerprintStateListener(
- new FingerprintStateListener() {
- @Nullable private Runnable mStateRunnable = null;
+ fingerprintManager.registerBiometricStateListener(
+ new BiometricStateListener() {
+ @Nullable
+ private Runnable mStateRunnable = null;
@Override
public void onStateChanged(
- @FingerprintStateListener.State int newState) {
+ @BiometricStateListener.State int newState) {
if (mStateRunnable != null) {
mHandler.removeCallbacks(mStateRunnable);
mStateRunnable = null;
@@ -198,11 +199,11 @@
// arrive in any order (success auth & power). Add a
// damper when moving to idle in case auth is first
if (newState == STATE_IDLE) {
- mStateRunnable = () -> mFingerprintState = newState;
+ mStateRunnable = () -> mBiometricState = newState;
mHandler.postDelayed(mStateRunnable,
DEBOUNCE_DELAY_MILLIS);
} else {
- mFingerprintState = newState;
+ mBiometricState = newState;
}
}
});
diff --git a/services/core/java/com/android/server/wm/BLASTSync.md b/services/core/java/com/android/server/wm/BLASTSync.md
index 2f39d6d..dbb28d4 100644
--- a/services/core/java/com/android/server/wm/BLASTSync.md
+++ b/services/core/java/com/android/server/wm/BLASTSync.md
@@ -106,3 +106,88 @@
at the same time as the state? We solve this by pushing all client communication through a handler thread that has to
acquire the lock. This ensures we uphold requirement 2.
+= Transaction ordering =
+
+Applying transactions from different process, and in to different server side transaction queues
+raises various questions about transaction ordering. There are two tricky questions in this
+domain that we address here:
+ 1. The ordering of Transactions from a single BLASTBufferQueue wrt to eachother
+ 2. The ordering of non synced WM updates to syncable state, wrt a BLASTSyncEngine
+ transaction
+
+== Ordering of Transactions in a single BBQ ==
+
+We can see if sync is never involved, there are never any real questions about ordering.
+Even using one-way setTransactionState, the calls are from a single thread to a single
+interface on another, and will be ordered. When we hand out transactions for sync
+is where issues can start to arise. Obviously if we apply another transaction
+immediately after handing out the sync transaction it could arrive first, and this would
+cause an ordering issue. It's also possible that the sync transaction arrives before the
+transaction applied before it (since setTransactionState is one way from BBQ). Even if
+the transactions are applied in the right order, it's possible for them to be
+commited out of sync, as the BBQ and SyncConsumer may be using different apply tokens
+resulting in the transaction being placed in different server side queues.
+
+To solve these issues, we use a scheme involving "barrier transactions". We show how
+this scheme handles every permutation of (Sync, NotSync).
+
+1. NotSync, NotSync: This is the trivial case. As long as both buffers are submitted from
+ the same thread, they will arrive in SF in order, and SF will place them in the same
+ queue (since there is a shared apply token), which it will process in order.
+2. Sync, NotSync: For sync transactions we register a commit callback, and require it to
+ be fired before applying the next transaction. Since the commit callback is only
+ fired when the transaction has latched on the server side, any transaction applied
+ later, must occur later.
+3. Sync, Sync: Ordering of consecutive sync transactions is delegated to the sync
+ consumer
+4. NotSync, Sync: This is the trickiest case, as we don't want to set a commit callback
+ on not sync transactions (as this would incur an unacceptable performance overhead).
+ Further complicating matters, we want to apply them with one-way binder, since
+ this is the hot path for all graphical updates. To solve this we use a
+ "setBufferHasBarrier" system. Sync transactions (before they are handed out)
+ are tagged with a barrier, referring to the frame number of the last
+ non sync transaction. SurfaceFlinger will ensure the correct ordering
+ by stalling transactions in the queue until barriers are fulfilled. This barrier
+ primitive is dangerous, because it could result in deadlocking, but its ok in
+ this scenario since only BBQ uses its apply token.
+
+We can see from this that all frames are in order.
+
+== Ordering of WM updates to syncable state ==
+
+A second interesting question, is about the ordering of WM updates to syncable-state. In
+the WM we frequently write code like
+ getPendingTransaction/getSyncTransaction().show(mSurfaceControl).
+In normal operation, getSyncTransaction and getPendingTransaction both refer to the same
+transaction which is the displaycontent pendingtransaction, applied by the WindowManager.
+During sync, each syncing container will instead use its mSyncTransaction, which will
+eventually be merged to be applied by the WindowManager. We can see that we have a congruent
+"problem" to BLASTBufferQueue transaction ordering. Namely, earlier state updates which were
+given to SysUI could end up being applied later than state updates which were made later but
+directly applied by the WM. We can break this down in to two cases:
+=== getPendingTransaction() and getSyncTransaction() ordering ===
+It's possible for code like this to occur:
+getSyncTransaction().OP1
+getPendingTransaction().OP2
+applyPendingTransaction
+applySyncTransaction
+
+in this case the change in OP2 was made later, but occurs first. We define this case as
+intended behavior, and say there is no ordering guarantee between the pending
+and sync transactions. This means the pending transaction is only useful in
+some marginal cases and should probably be considered a deprecated primitive.
+=== getSyncTransaction() and getSyncTransaction() ordering ===
+However, we take great care to ensure usage of getSyncTransaction() reflects
+the ordering the developer would expect. BLASTSyncEngine will register
+a commit callback on all transactions it hands out. In the interval between
+receiving this commit callback and sending out the transaction, we may have other
+data enter getSyncTransaction. If we returned the pending transaction
+(as we do in normal time), then we could create ordering issues, since the pending
+transactions ordering is undefined. Instead we continue to return the sync transaction
+during this interval. If no second sync has started by the time we receive
+the commit callback, then we directly apply this left over data in the sync transaction
+guaranteed it will be ordered correctly, and return to using the pending
+transaction. If a second sync has started, then we just allow the data
+to persist in the mSyncTransaction, potentially to be overwritten
+by the new sync. It will eventually apply with SysUI's apply token and
+ordering will be maintained.
diff --git a/services/core/java/com/android/server/wm/BLASTSyncEngine.java b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
index 6e205be..3f300bc 100644
--- a/services/core/java/com/android/server/wm/BLASTSyncEngine.java
+++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
@@ -19,6 +19,7 @@
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SYNC_ENGINE;
+import static com.android.server.wm.WindowManagerService.H.WINDOW_STATE_BLAST_SYNC_TIMEOUT;
import android.annotation.NonNull;
import android.os.Trace;
@@ -147,6 +148,33 @@
for (WindowContainer wc : mRootMembers) {
wc.finishSync(merged, false /* cancel */);
}
+
+ final ArraySet<WindowContainer> wcAwaitingCommit = new ArraySet<>();
+ for (WindowContainer wc : mRootMembers) {
+ wc.waitForSyncTransactionCommit(wcAwaitingCommit);
+ }
+ final Runnable callback = new Runnable() {
+ // Can run a second time if the action completes after the timeout.
+ boolean ran = false;
+ public void run() {
+ synchronized (mWm.mGlobalLock) {
+ if (ran) {
+ return;
+ }
+ mWm.mH.removeCallbacks(this);
+ ran = true;
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ for (WindowContainer wc : wcAwaitingCommit) {
+ wc.onSyncTransactionCommitted(t);
+ }
+ t.apply();
+ wcAwaitingCommit.clear();
+ }
+ }
+ };
+ merged.addTransactionCommittedListener((r) -> { r.run(); }, callback::run);
+ mWm.mH.postDelayed(callback, WINDOW_STATE_BLAST_SYNC_TIMEOUT);
+
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "onTransactionReady");
mListener.onTransactionReady(mSyncId, merged);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index eaf82b6..2d7d705 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -138,8 +138,8 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.policy.ForceShowNavigationBarSettingsObserver;
import com.android.internal.policy.GestureNavigationSettingsObserver;
+import com.android.internal.policy.KidsModeSettingsObserver;
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.internal.policy.SystemBarUtils;
import com.android.internal.protolog.common.ProtoLog;
@@ -378,7 +378,7 @@
private final WindowManagerInternal.AppTransitionListener mAppTransitionListener;
- private final ForceShowNavigationBarSettingsObserver mForceShowNavigationBarSettingsObserver;
+ private final KidsModeSettingsObserver mKidsModeSettingsObserver;
private boolean mForceShowNavigationBarEnabled;
private class PolicyHandler extends Handler {
@@ -653,17 +653,17 @@
});
mHandler.post(mGestureNavigationSettingsObserver::register);
- mForceShowNavigationBarSettingsObserver = new ForceShowNavigationBarSettingsObserver(
+ mKidsModeSettingsObserver = new KidsModeSettingsObserver(
mHandler, mContext);
- mForceShowNavigationBarSettingsObserver.setOnChangeRunnable(() -> {
+ mKidsModeSettingsObserver.setOnChangeRunnable(() -> {
synchronized (mLock) {
mForceShowNavigationBarEnabled =
- mForceShowNavigationBarSettingsObserver.isEnabled();
+ mKidsModeSettingsObserver.isEnabled();
updateSystemBarAttributes();
}
});
- mForceShowNavigationBarEnabled = mForceShowNavigationBarSettingsObserver.isEnabled();
- mHandler.post(mForceShowNavigationBarSettingsObserver::register);
+ mForceShowNavigationBarEnabled = mKidsModeSettingsObserver.isEnabled();
+ mHandler.post(mKidsModeSettingsObserver::register);
}
/**
@@ -2861,7 +2861,7 @@
void release() {
mDisplayContent.mTransitionController.unregisterLegacyListener(mAppTransitionListener);
mHandler.post(mGestureNavigationSettingsObserver::unregister);
- mHandler.post(mForceShowNavigationBarSettingsObserver::unregister);
+ mHandler.post(mKidsModeSettingsObserver::unregister);
mImmersiveModeConfirmation.release();
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index fc407e6..efe617d 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -445,7 +445,7 @@
}
final int taskCount = visibleTasks.size();
- for (int i = 0; i < taskCount; i++) {
+ for (int i = taskCount - 1; i >= 0; i--) {
final Task task = visibleTasks.get(i);
if (skipAnimation(task)) {
continue;
@@ -746,7 +746,7 @@
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
"collectTaskRemoteAnimations, target: %s", target);
}
- }, true);
+ }, false /* traverseTopToBottom */);
}
void logRecentsAnimationStartTime(int durationMs) {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 6f69e03..22714c6 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2007,8 +2007,7 @@
r.getDisplayContent().prepareAppTransition(TRANSIT_NONE);
final TaskFragment organizedTf = r.getOrganizedTaskFragment();
- // TODO: Does it make sense to only count non-finishing activities?
- final boolean singleActivity = task.getActivityCount() == 1;
+ final boolean singleActivity = task.getNonFinishingActivityCount() == 1;
final Task rootTask;
if (singleActivity) {
rootTask = task;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index bd078d8..9ea566e 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -1380,14 +1380,6 @@
return getActivity(ActivityRecord::canBeTopRunning);
}
- int getActivityCount() {
- final int[] activityCount = new int[1];
- forAllActivities(ar -> {
- activityCount[0]++;
- });
- return activityCount[0];
- }
-
/**
* Return true if any activities in this task belongs to input uid.
*/
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 4e0d84c..e0346544 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -1034,19 +1034,19 @@
// If the top activity is the resumed one, nothing to do.
if (mResumedActivity == next && next.isState(RESUMED)
&& taskDisplayArea.allResumedActivitiesComplete()) {
+ // Ensure the visibility gets updated before execute app transition.
+ taskDisplayArea.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
+ false /* preserveWindows */, true /* notifyClients */);
// Make sure we have executed any pending transitions, since there
// should be nothing left to do at this point.
executeAppTransition(options);
- // For devices that are not in fullscreen mode (e.g. freeform windows), it's possible
- // we still want to check if the visibility of other windows have changed (e.g. bringing
- // a fullscreen window forward to cover another freeform activity.)
- if (taskDisplayArea.inMultiWindowMode()) {
- if (taskDisplayArea.mDisplayContent != null
- && taskDisplayArea.mDisplayContent.mFocusedApp != next) {
- taskDisplayArea.mDisplayContent.setFocusedApp(next);
- }
- taskDisplayArea.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
- false /* preserveWindows */, true /* notifyClients */);
+
+ // In a multi-resumed environment, like in a freeform device, the top
+ // activity can be resumed, but it might not be the focused app.
+ // Set focused app when top activity is resumed
+ if (taskDisplayArea.inMultiWindowMode() && taskDisplayArea.mDisplayContent != null
+ && taskDisplayArea.mDisplayContent.mFocusedApp != next) {
+ taskDisplayArea.mDisplayContent.setFocusedApp(next);
}
ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Top activity "
+ "resumed %s", next);
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 4dbcea1..f5af2b4 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -236,6 +236,8 @@
*/
private boolean mCommittedReparentToAnimationLeash;
+ private int mSyncTransactionCommitCallbackDepth = 0;
+
/** Interface for {@link #isAnimating} to check which cases for the container is animating. */
public interface AnimationFlags {
/**
@@ -2688,6 +2690,9 @@
* {@link #getPendingTransaction()}
*/
public Transaction getSyncTransaction() {
+ if (mSyncTransactionCommitCallbackDepth > 0) {
+ return mSyncTransaction;
+ }
if (mSyncState != SYNC_STATE_NONE) {
return mSyncTransaction;
}
@@ -3909,4 +3914,29 @@
p.updateOverlayInsetsState(originalChange);
}
}
+
+ void waitForSyncTransactionCommit(ArraySet<WindowContainer> wcAwaitingCommit) {
+ if (wcAwaitingCommit.contains(this)) {
+ return;
+ }
+ mSyncTransactionCommitCallbackDepth++;
+ wcAwaitingCommit.add(this);
+
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ mChildren.get(i).waitForSyncTransactionCommit(wcAwaitingCommit);
+ }
+ }
+
+ void onSyncTransactionCommitted(SurfaceControl.Transaction t) {
+ mSyncTransactionCommitCallbackDepth--;
+ if (mSyncTransactionCommitCallbackDepth > 0) {
+ return;
+ }
+ if (mSyncState != SYNC_STATE_NONE) {
+ return;
+ }
+
+ t.merge(mSyncTransaction);
+ }
+
}
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index c1c8b81..67f7ff7 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -1522,7 +1522,10 @@
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
return 0;
}
- if (taskFragment.isEmbeddedTaskFragmentInPip()) {
+ if (taskFragment.isEmbeddedTaskFragmentInPip()
+ // When the Task enters PiP before the organizer removes the empty TaskFragment, we
+ // should allow it to do the cleanup.
+ && taskFragment.getTopNonFinishingActivity() != null) {
final Throwable exception = new IllegalArgumentException(
"Not allowed to delete TaskFragment in PIP Task");
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
index c0b4f0f..ac54293 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
@@ -585,6 +585,7 @@
DeviceConfigSession<Float> bgCurrentDrainRestrictedBucketThreshold = null;
DeviceConfigSession<Float> bgCurrentDrainBgRestrictedThreshold = null;
DeviceConfigSession<Boolean> bgPromptFgsWithNotiToBgRestricted = null;
+ DeviceConfigSession<Boolean> bgPromptAbusiveAppToBgRestricted = null;
DeviceConfigSession<Long> bgNotificationMinInterval = null;
DeviceConfigSession<Integer> bgBatteryExemptionTypes = null;
DeviceConfigSession<Boolean> bgCurrentDrainDecoupleThresholds = null;
@@ -642,6 +643,14 @@
R.bool.config_bg_prompt_fgs_with_noti_to_bg_restricted));
bgPromptFgsWithNotiToBgRestricted.set(true);
+ bgPromptAbusiveAppToBgRestricted = new DeviceConfigSession<>(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ ConstantsObserver.KEY_BG_PROMPT_ABUSIVE_APPS_TO_BG_RESTRICTED,
+ DeviceConfig::getBoolean,
+ mContext.getResources().getBoolean(
+ R.bool.config_bg_prompt_abusive_apps_to_bg_restricted));
+ bgPromptAbusiveAppToBgRestricted.set(true);
+
bgNotificationMinInterval = new DeviceConfigSession<>(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
ConstantsObserver.KEY_BG_ABUSIVE_NOTIFICATION_MINIMAL_INTERVAL,
@@ -1055,6 +1064,7 @@
closeIfNotNull(bgCurrentDrainRestrictedBucketThreshold);
closeIfNotNull(bgCurrentDrainBgRestrictedThreshold);
closeIfNotNull(bgPromptFgsWithNotiToBgRestricted);
+ closeIfNotNull(bgPromptAbusiveAppToBgRestricted);
closeIfNotNull(bgNotificationMinInterval);
closeIfNotNull(bgBatteryExemptionTypes);
closeIfNotNull(bgCurrentDrainDecoupleThresholds);
@@ -1613,6 +1623,7 @@
DeviceConfigSession<String> bgPermissionsInMonitor = null;
DeviceConfigSession<Boolean> bgCurrentDrainHighThresholdByBgLocation = null;
DeviceConfigSession<Boolean> bgCurrentDrainDecoupleThresholds = null;
+ DeviceConfigSession<Boolean> bgPromptAbusiveAppToBgRestricted = null;
mBgRestrictionController.addAppBackgroundRestrictionListener(listener);
@@ -1751,6 +1762,14 @@
AppBatteryPolicy.DEFAULT_BG_CURRENT_DRAIN_DECOUPLE_THRESHOLD);
bgCurrentDrainDecoupleThresholds.set(true);
+ bgPromptAbusiveAppToBgRestricted = new DeviceConfigSession<>(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ ConstantsObserver.KEY_BG_PROMPT_ABUSIVE_APPS_TO_BG_RESTRICTED,
+ DeviceConfig::getBoolean,
+ mContext.getResources().getBoolean(
+ R.bool.config_bg_prompt_abusive_apps_to_bg_restricted));
+ bgPromptAbusiveAppToBgRestricted.set(true);
+
mCurrentTimeMillis = 10_000L;
doReturn(mCurrentTimeMillis - windowMs).when(stats).getStatsStartTimestamp();
doReturn(mCurrentTimeMillis).when(stats).getStatsEndTimestamp();
@@ -2168,6 +2187,7 @@
closeIfNotNull(bgBatteryExemptionTypes);
closeIfNotNull(bgPermissionMonitorEnabled);
closeIfNotNull(bgPermissionsInMonitor);
+ closeIfNotNull(bgPromptAbusiveAppToBgRestricted);
closeIfNotNull(bgCurrentDrainHighThresholdByBgLocation);
closeIfNotNull(bgCurrentDrainDecoupleThresholds);
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallbackTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/BiometricStateCallbackTest.java
similarity index 82%
rename from services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallbackTest.java
rename to services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/BiometricStateCallbackTest.java
index 38e8dfa..5f88c99 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallbackTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/BiometricStateCallbackTest.java
@@ -24,12 +24,13 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.hardware.fingerprint.FingerprintStateListener;
+import android.hardware.biometrics.BiometricStateListener;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
import com.android.server.biometrics.sensors.AuthenticationClient;
+import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.EnrollClient;
import org.junit.Before;
@@ -39,19 +40,19 @@
@Presubmit
@SmallTest
-public class FingerprintStateCallbackTest {
+public class BiometricStateCallbackTest {
- private FingerprintStateCallback mCallback;
+ private BiometricStateCallback mCallback;
@Mock
- FingerprintStateListener mFingerprintStateListener;
+ BiometricStateListener mBiometricStateListener;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- mCallback = new FingerprintStateCallback();
- mCallback.registerFingerprintStateListener(mFingerprintStateListener);
+ mCallback = new BiometricStateCallback();
+ mCallback.registerBiometricStateListener(mBiometricStateListener);
}
@Test
@@ -86,10 +87,10 @@
mCallback.onClientFinished(client, true /* success */);
if (expectCallback) {
- verify(mFingerprintStateListener).onEnrollmentsChanged(eq(userId), eq(sensorId),
+ verify(mBiometricStateListener).onEnrollmentsChanged(eq(userId), eq(sensorId),
eq(expectedCallbackValue));
} else {
- verify(mFingerprintStateListener, never()).onEnrollmentsChanged(anyInt(), anyInt(),
+ verify(mBiometricStateListener, never()).onEnrollmentsChanged(anyInt(), anyInt(),
anyBoolean());
}
}
@@ -98,7 +99,7 @@
public void testAuthentication_enrollmentCallbackNeverNotified() {
AuthenticationClient<?> client = mock(AuthenticationClient.class);
mCallback.onClientFinished(client, true /* success */);
- verify(mFingerprintStateListener, never()).onEnrollmentsChanged(anyInt(), anyInt(),
+ verify(mBiometricStateListener, never()).onEnrollmentsChanged(anyInt(), anyInt(),
anyBoolean());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
index 5a1a02e..c6ddf27 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
@@ -42,9 +42,9 @@
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.sensors.BiometricScheduler;
+import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.HalClientMonitor;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
-import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
import org.junit.Before;
@@ -71,7 +71,7 @@
@Mock
private GestureAvailabilityDispatcher mGestureAvailabilityDispatcher;
@Mock
- private FingerprintStateCallback mFingerprintStateCallback;
+ private BiometricStateCallback mBiometricStateCallback;
@Mock
private BiometricContext mBiometricContext;
@@ -107,7 +107,7 @@
mLockoutResetDispatcher = new LockoutResetDispatcher(mContext);
mFingerprintProvider = new TestableFingerprintProvider(mDaemon, mContext,
- mFingerprintStateCallback, mSensorProps, TAG, mLockoutResetDispatcher,
+ mBiometricStateCallback, mSensorProps, TAG, mLockoutResetDispatcher,
mGestureAvailabilityDispatcher, mBiometricContext);
}
@@ -156,13 +156,13 @@
TestableFingerprintProvider(@NonNull IFingerprint daemon,
@NonNull Context context,
- @NonNull FingerprintStateCallback fingerprintStateCallback,
+ @NonNull BiometricStateCallback biometricStateCallback,
@NonNull SensorProps[] props,
@NonNull String halInstanceName,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
@NonNull BiometricContext biometricContext) {
- super(context, fingerprintStateCallback, props, halInstanceName, lockoutResetDispatcher,
+ super(context, biometricStateCallback, props, halInstanceName, lockoutResetDispatcher,
gestureAvailabilityDispatcher, biometricContext);
mDaemon = daemon;
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java
index 529f994..b32b89a 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java
@@ -41,8 +41,8 @@
import com.android.internal.R;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.sensors.BiometricScheduler;
+import com.android.server.biometrics.sensors.BiometricStateCallback;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
-import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback;
import org.junit.Before;
import org.junit.Test;
@@ -70,7 +70,7 @@
@Mock
private BiometricScheduler mScheduler;
@Mock
- private FingerprintStateCallback mFingerprintStateCallback;
+ private BiometricStateCallback mBiometricStateCallback;
@Mock
private BiometricContext mBiometricContext;
@@ -102,7 +102,7 @@
componentInfo, FingerprintSensorProperties.TYPE_UNKNOWN,
resetLockoutRequiresHardwareAuthToken);
- mFingerprint21 = new TestableFingerprint21(mContext, mFingerprintStateCallback, sensorProps,
+ mFingerprint21 = new TestableFingerprint21(mContext, mBiometricStateCallback, sensorProps,
mScheduler, new Handler(Looper.getMainLooper()), mLockoutResetDispatcher,
mHalResultController, mBiometricContext);
}
@@ -125,13 +125,13 @@
private static class TestableFingerprint21 extends Fingerprint21 {
TestableFingerprint21(@NonNull Context context,
- @NonNull FingerprintStateCallback fingerprintStateCallback,
+ @NonNull BiometricStateCallback biometricStateCallback,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull BiometricScheduler scheduler, @NonNull Handler handler,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull HalResultController controller,
@NonNull BiometricContext biometricContext) {
- super(context, fingerprintStateCallback, sensorProps, scheduler, handler,
+ super(context, biometricStateCallback, sensorProps, scheduler, handler,
lockoutResetDispatcher, controller, biometricContext);
}
diff --git a/services/tests/servicestests/src/com/android/server/policy/SideFpsEventHandlerTest.java b/services/tests/servicestests/src/com/android/server/policy/SideFpsEventHandlerTest.java
index 41c7e31..371861f 100644
--- a/services/tests/servicestests/src/com/android/server/policy/SideFpsEventHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/policy/SideFpsEventHandlerTest.java
@@ -26,9 +26,9 @@
import android.app.AlertDialog;
import android.content.pm.PackageManager;
+import android.hardware.biometrics.BiometricStateListener;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
-import android.hardware.fingerprint.FingerprintStateListener;
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
import android.os.Handler;
import android.os.PowerManager;
@@ -61,11 +61,11 @@
public class SideFpsEventHandlerTest {
private static final List<Integer> sAllStates = List.of(
- FingerprintStateListener.STATE_IDLE,
- FingerprintStateListener.STATE_ENROLLING,
- FingerprintStateListener.STATE_KEYGUARD_AUTH,
- FingerprintStateListener.STATE_BP_AUTH,
- FingerprintStateListener.STATE_AUTH_OTHER);
+ BiometricStateListener.STATE_IDLE,
+ BiometricStateListener.STATE_ENROLLING,
+ BiometricStateListener.STATE_KEYGUARD_AUTH,
+ BiometricStateListener.STATE_BP_AUTH,
+ BiometricStateListener.STATE_AUTH_OTHER);
@Rule
public TestableContext mContext =
@@ -83,7 +83,7 @@
private TestLooper mLooper = new TestLooper();
private SideFpsEventHandler mEventHandler;
- private FingerprintStateListener mFingerprintStateListener;
+ private BiometricStateListener mBiometricStateListener;
@Before
public void setup() {
@@ -116,7 +116,7 @@
setupWithSensor(false /* hasSfps */, true /* initialized */);
for (int state : sAllStates) {
- setFingerprintState(state);
+ setBiometricState(state);
assertThat(mEventHandler.onSinglePressDetected(200L)).isFalse();
mLooper.dispatchAll();
@@ -129,7 +129,7 @@
setupWithSensor(true /* hasSfps */, false /* initialized */);
for (int state : sAllStates) {
- setFingerprintState(state);
+ setBiometricState(state);
assertThat(mEventHandler.onSinglePressDetected(400L)).isFalse();
mLooper.dispatchAll();
@@ -141,10 +141,10 @@
public void ignoresWhenIdleOrUnknown() throws Exception {
setupWithSensor(true /* hasSfps */, true /* initialized */);
- setFingerprintState(FingerprintStateListener.STATE_IDLE);
+ setBiometricState(BiometricStateListener.STATE_IDLE);
assertThat(mEventHandler.onSinglePressDetected(80000L)).isFalse();
- setFingerprintState(FingerprintStateListener.STATE_AUTH_OTHER);
+ setBiometricState(BiometricStateListener.STATE_AUTH_OTHER);
assertThat(mEventHandler.onSinglePressDetected(90000L)).isFalse();
mLooper.dispatchAll();
@@ -155,7 +155,7 @@
public void ignoresOnKeyguard() throws Exception {
setupWithSensor(true /* hasSfps */, true /* initialized */);
- setFingerprintState(FingerprintStateListener.STATE_KEYGUARD_AUTH);
+ setBiometricState(BiometricStateListener.STATE_KEYGUARD_AUTH);
assertThat(mEventHandler.onSinglePressDetected(80000L)).isFalse();
mLooper.dispatchAll();
@@ -166,7 +166,7 @@
public void promptsWhenBPisActive() throws Exception {
setupWithSensor(true /* hasSfps */, true /* initialized */);
- setFingerprintState(FingerprintStateListener.STATE_BP_AUTH);
+ setBiometricState(BiometricStateListener.STATE_BP_AUTH);
assertThat(mEventHandler.onSinglePressDetected(80000L)).isTrue();
mLooper.dispatchAll();
@@ -177,16 +177,16 @@
public void promptsWhenEnrolling() throws Exception {
setupWithSensor(true /* hasSfps */, true /* initialized */);
- setFingerprintState(FingerprintStateListener.STATE_ENROLLING);
+ setBiometricState(BiometricStateListener.STATE_ENROLLING);
assertThat(mEventHandler.onSinglePressDetected(80000L)).isTrue();
mLooper.dispatchAll();
verify(mAlertDialog).show();
}
- private void setFingerprintState(@FingerprintStateListener.State int newState) {
- if (mFingerprintStateListener != null) {
- mFingerprintStateListener.onStateChanged(newState);
+ private void setBiometricState(@BiometricStateListener.State int newState) {
+ if (mBiometricStateListener != null) {
+ mBiometricStateListener.onStateChanged(newState);
mLooper.dispatchAll();
}
}
@@ -204,10 +204,10 @@
fpCallbackCaptor.getValue().onAllAuthenticatorsRegistered(
List.of(mock(FingerprintSensorPropertiesInternal.class)));
if (hasSfps) {
- ArgumentCaptor<FingerprintStateListener> captor = ArgumentCaptor.forClass(
- FingerprintStateListener.class);
- verify(mFingerprintManager).registerFingerprintStateListener(captor.capture());
- mFingerprintStateListener = captor.getValue();
+ ArgumentCaptor<BiometricStateListener> captor = ArgumentCaptor.forClass(
+ BiometricStateListener.class);
+ verify(mFingerprintManager).registerBiometricStateListener(captor.capture());
+ mBiometricStateListener = captor.getValue();
}
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index d135de0..a297608 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -527,6 +527,14 @@
verify(mAtm.mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
eq(errorToken), any(IllegalArgumentException.class));
assertNotNull(mAtm.mWindowOrganizerController.getTaskFragment(mFragmentToken));
+
+ // Allow organizer to delete empty TaskFragment for cleanup.
+ final Task task = mTaskFragment.getTask();
+ mTaskFragment.removeChild(mTaskFragment.getTopMostActivity());
+ mAtm.mWindowOrganizerController.applyTransaction(mTransaction);
+
+ assertNull(mAtm.mWindowOrganizerController.getTaskFragment(mFragmentToken));
+ assertNull(task.getTopChild());
}
@Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeEditorPopupDialogTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeEditorPopupDialogTest.kt
index bff099e..6257484 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeEditorPopupDialogTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeEditorPopupDialogTest.kt
@@ -91,6 +91,7 @@
.then()
.isVisible(FlickerComponentName.IME_SNAPSHOT)
.then()
+ .isInvisible(FlickerComponentName.IME_SNAPSHOT)
.isInvisible(FlickerComponentName.IME)
}
}
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index bb98bc0..54b3c40 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -65,6 +65,7 @@
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.TelephonyNetworkSpecifier;
+import android.net.Uri;
import android.net.vcn.IVcnStatusCallback;
import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
import android.net.vcn.VcnConfig;
@@ -114,18 +115,24 @@
public class VcnManagementServiceTest {
private static final String TEST_PACKAGE_NAME =
VcnManagementServiceTest.class.getPackage().getName();
+ private static final String TEST_PACKAGE_NAME_2 = "TEST_PKG_2";
private static final String TEST_CB_PACKAGE_NAME =
VcnManagementServiceTest.class.getPackage().getName() + ".callback";
private static final ParcelUuid TEST_UUID_1 = new ParcelUuid(new UUID(0, 0));
private static final ParcelUuid TEST_UUID_2 = new ParcelUuid(new UUID(1, 1));
+ private static final ParcelUuid TEST_UUID_3 = new ParcelUuid(new UUID(2, 2));
private static final VcnConfig TEST_VCN_CONFIG;
+ private static final VcnConfig TEST_VCN_CONFIG_PKG_2;
private static final int TEST_UID = Process.FIRST_APPLICATION_UID;
static {
final Context mockConfigContext = mock(Context.class);
- doReturn(TEST_PACKAGE_NAME).when(mockConfigContext).getOpPackageName();
+ doReturn(TEST_PACKAGE_NAME).when(mockConfigContext).getOpPackageName();
TEST_VCN_CONFIG = VcnConfigTest.buildTestConfig(mockConfigContext);
+
+ doReturn(TEST_PACKAGE_NAME_2).when(mockConfigContext).getOpPackageName();
+ TEST_VCN_CONFIG_PKG_2 = VcnConfigTest.buildTestConfig(mockConfigContext);
}
private static final Map<ParcelUuid, VcnConfig> TEST_VCN_CONFIG_MAP =
@@ -246,18 +253,24 @@
eq(android.Manifest.permission.NETWORK_FACTORY), any());
}
+
private void setupMockedCarrierPrivilege(boolean isPrivileged) {
+ setupMockedCarrierPrivilege(isPrivileged, TEST_PACKAGE_NAME);
+ }
+
+ private void setupMockedCarrierPrivilege(boolean isPrivileged, String pkg) {
doReturn(Collections.singletonList(TEST_SUBSCRIPTION_INFO))
.when(mSubMgr)
.getSubscriptionsInGroup(any());
doReturn(mTelMgr)
.when(mTelMgr)
.createForSubscriptionId(eq(TEST_SUBSCRIPTION_INFO.getSubscriptionId()));
- doReturn(isPrivileged
- ? CARRIER_PRIVILEGE_STATUS_HAS_ACCESS
- : CARRIER_PRIVILEGE_STATUS_NO_ACCESS)
+ doReturn(
+ isPrivileged
+ ? CARRIER_PRIVILEGE_STATUS_HAS_ACCESS
+ : CARRIER_PRIVILEGE_STATUS_NO_ACCESS)
.when(mTelMgr)
- .checkCarrierPrivilegesForPackage(eq(TEST_PACKAGE_NAME));
+ .checkCarrierPrivilegesForPackage(eq(pkg));
}
@Test
@@ -414,7 +427,13 @@
private BroadcastReceiver getPackageChangeReceiver() {
final ArgumentCaptor<BroadcastReceiver> captor =
ArgumentCaptor.forClass(BroadcastReceiver.class);
- verify(mMockContext).registerReceiver(captor.capture(), any(), any(), any());
+ verify(mMockContext).registerReceiver(captor.capture(), argThat(filter -> {
+ return filter.hasAction(Intent.ACTION_PACKAGE_ADDED)
+ && filter.hasAction(Intent.ACTION_PACKAGE_REPLACED)
+ && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED)
+ && filter.hasAction(Intent.ACTION_PACKAGE_DATA_CLEARED)
+ && filter.hasAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
+ }), any(), any());
return captor.getValue();
}
@@ -539,6 +558,44 @@
}
@Test
+ public void testPackageChangeListener_packageDataCleared() throws Exception {
+ triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_1, Collections.singleton(TEST_UUID_1));
+ final Vcn vcn = mVcnMgmtSvc.getAllVcns().get(TEST_UUID_1);
+
+ final BroadcastReceiver receiver = getPackageChangeReceiver();
+ assertEquals(TEST_VCN_CONFIG_MAP, mVcnMgmtSvc.getConfigs());
+
+ final Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED);
+ intent.setData(Uri.parse("package:" + TEST_PACKAGE_NAME));
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(TEST_UID));
+
+ receiver.onReceive(mMockContext, intent);
+ mTestLooper.dispatchAll();
+ verify(vcn).teardownAsynchronously();
+ assertTrue(mVcnMgmtSvc.getConfigs().isEmpty());
+ verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
+ }
+
+ @Test
+ public void testPackageChangeListener_packageFullyRemoved() throws Exception {
+ triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_1, Collections.singleton(TEST_UUID_1));
+ final Vcn vcn = mVcnMgmtSvc.getAllVcns().get(TEST_UUID_1);
+
+ final BroadcastReceiver receiver = getPackageChangeReceiver();
+ assertEquals(TEST_VCN_CONFIG_MAP, mVcnMgmtSvc.getConfigs());
+
+ final Intent intent = new Intent(Intent.ACTION_PACKAGE_FULLY_REMOVED);
+ intent.setData(Uri.parse("package:" + TEST_PACKAGE_NAME));
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(TEST_UID));
+
+ receiver.onReceive(mMockContext, intent);
+ mTestLooper.dispatchAll();
+ verify(vcn).teardownAsynchronously();
+ assertTrue(mVcnMgmtSvc.getConfigs().isEmpty());
+ verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
+ }
+
+ @Test
public void testSetVcnConfigRequiresNonSystemServer() throws Exception {
doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid();
@@ -578,7 +635,7 @@
@Test
public void testSetVcnConfigMismatchedPackages() throws Exception {
try {
- mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, "IncorrectPackage");
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, TEST_PACKAGE_NAME_2);
fail("Expected exception due to mismatched packages in config and method call");
} catch (IllegalArgumentException expected) {
verify(mMockPolicyListener, never()).onPolicyChanged();
@@ -678,11 +735,12 @@
}
@Test
- public void testClearVcnConfigRequiresCarrierPrivileges() throws Exception {
+ public void testClearVcnConfigRequiresCarrierPrivilegesOrProvisioningPackage()
+ throws Exception {
setupMockedCarrierPrivilege(false);
try {
- mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME);
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME_2);
fail("Expected security exception for missing carrier privileges");
} catch (SecurityException expected) {
}
@@ -691,20 +749,32 @@
@Test
public void testClearVcnConfigMismatchedPackages() throws Exception {
try {
- mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, "IncorrectPackage");
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME_2);
fail("Expected security exception due to mismatched packages");
} catch (SecurityException expected) {
}
}
@Test
- public void testClearVcnConfig() throws Exception {
+ public void testClearVcnConfig_callerIsProvisioningPackage() throws Exception {
+ // Lose carrier privileges to test that provisioning package is sufficient.
+ setupMockedCarrierPrivilege(false);
+
mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME);
assertTrue(mVcnMgmtSvc.getConfigs().isEmpty());
verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
}
@Test
+ public void testClearVcnConfig_callerIsCarrierPrivileged() throws Exception {
+ setupMockedCarrierPrivilege(true, TEST_PACKAGE_NAME_2);
+
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME_2);
+ assertTrue(mVcnMgmtSvc.getConfigs().isEmpty());
+ verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
+ }
+
+ @Test
public void testClearVcnConfigNotifiesStatusCallback() throws Exception {
setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isActive */);
mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME);
@@ -755,11 +825,12 @@
@Test
public void testGetConfiguredSubscriptionGroupsMismatchedPackages() throws Exception {
- final String badPackage = "IncorrectPackage";
- doThrow(new SecurityException()).when(mAppOpsMgr).checkPackage(TEST_UID, badPackage);
+ doThrow(new SecurityException())
+ .when(mAppOpsMgr)
+ .checkPackage(TEST_UID, TEST_PACKAGE_NAME_2);
try {
- mVcnMgmtSvc.getConfiguredSubscriptionGroups(badPackage);
+ mVcnMgmtSvc.getConfiguredSubscriptionGroups(TEST_PACKAGE_NAME_2);
fail("Expected security exception due to mismatched packages");
} catch (SecurityException expected) {
}
@@ -767,14 +838,16 @@
@Test
public void testGetConfiguredSubscriptionGroups() throws Exception {
+ setupMockedCarrierPrivilege(true, TEST_PACKAGE_NAME_2);
mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
+ mVcnMgmtSvc.setVcnConfig(TEST_UUID_3, TEST_VCN_CONFIG_PKG_2, TEST_PACKAGE_NAME_2);
- // Assert that if both UUID 1 and 2 are provisioned, the caller only gets ones that they are
- // privileged for.
+ // Assert that if UUIDs 1, 2 and 3 are provisioned, the caller only gets ones that they are
+ // privileged for, or are the provisioning package of.
triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_1, Collections.singleton(TEST_UUID_1));
final List<ParcelUuid> subGrps =
mVcnMgmtSvc.getConfiguredSubscriptionGroups(TEST_PACKAGE_NAME);
- assertEquals(Collections.singletonList(TEST_UUID_1), subGrps);
+ assertEquals(Arrays.asList(new ParcelUuid[] {TEST_UUID_1, TEST_UUID_2}), subGrps);
}
@Test