Merge "Fix tap outside focus for SCVH from different process." into udc-dev
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 887ee5f..644d92c 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -33,6 +33,7 @@
import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
import android.app.IUidObserver;
+import android.app.UidObserver;
import android.app.compat.CompatChanges;
import android.app.job.IJobScheduler;
import android.app.job.IUserVisibleJobObserver;
@@ -1250,7 +1251,7 @@
return pkg;
}
- final private IUidObserver mUidObserver = new IUidObserver.Stub() {
+ final private IUidObserver mUidObserver = new UidObserver() {
@Override public void onUidStateChanged(int uid, int procState, long procStateSeq,
int capability) {
final SomeArgs args = SomeArgs.obtain();
@@ -1264,19 +1265,13 @@
mHandler.obtainMessage(MSG_UID_GONE, uid, disabled ? 1 : 0).sendToTarget();
}
- @Override public void onUidActive(int uid) throws RemoteException {
+ @Override public void onUidActive(int uid) {
mHandler.obtainMessage(MSG_UID_ACTIVE, uid, 0).sendToTarget();
}
@Override public void onUidIdle(int uid, boolean disabled) {
mHandler.obtainMessage(MSG_UID_IDLE, uid, disabled ? 1 : 0).sendToTarget();
}
-
- @Override public void onUidCachedChanged(int uid, boolean cached) {
- }
-
- @Override public void onUidProcAdjChanged(int uid) {
- }
};
public Context getTestableContext() {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 7aedd30..96d785f 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4067,8 +4067,9 @@
* notification if alerts for this notification's group should be handled by a different
* notification. This is only applicable for notifications that belong to a
* {@link #setGroup(String) group}. This must be called on all notifications you want to
- * mute. For example, if you want only the summary of your group to make noise, all
- * children in the group should have the group alert behavior {@link #GROUP_ALERT_SUMMARY}.
+ * mute. For example, if you want only the summary of your group to make noise and/or peek
+ * on screen, all children in the group should have the group alert behavior
+ * {@link #GROUP_ALERT_SUMMARY}.
*
* <p> The default value is {@link #GROUP_ALERT_ALL}.</p>
*/
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index bad6c77..7dabe60 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -6413,7 +6413,7 @@
public void lockNow(@LockNowFlag int flags) {
if (mService != null) {
try {
- mService.lockNow(flags, mParentInstance);
+ mService.lockNow(flags, mContext.getPackageName(), mParentInstance);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -13646,8 +13646,8 @@
* privacy-sensitive events happening outside the managed profile would have been redacted
* already.
*
- * @param admin Which device admin this request is associated with. Null if the caller is not
- * a device admin
+ * @param admin Which device admin this request is associated with, or {@code null}
+ * if called by a delegated app.
* @param enabled whether security logging should be enabled or not.
* @throws SecurityException if the caller is not permitted to control security logging.
* @see #setAffiliationIds
@@ -13699,8 +13699,8 @@
* it must be affiliated with the device. Otherwise a {@link SecurityException} will be thrown.
* See {@link #isAffiliatedUser}.
*
- * @param admin Which device admin this request is associated with. Null if the caller is not
- * a device admin.
+ * @param admin Which device admin this request is associated with, or {@code null}
+ * if called by a delegated app.
* @return the new batch of security logs which is a list of {@link SecurityEvent},
* or {@code null} if rate limitation is exceeded or if logging is currently disabled.
* @throws SecurityException if the caller is not allowed to access security logging,
@@ -13857,8 +13857,8 @@
* it must be affiliated with the device. Otherwise a {@link SecurityException} will be thrown.
* See {@link #isAffiliatedUser}.
*
- * @param admin Which device admin this request is associated with. Null if the caller is not
- * a device admin.
+ * @param admin Which device admin this request is associated with, or {@code null}
+ * if called by a delegated app.
* @return Device logs from before the latest reboot of the system, or {@code null} if this API
* is not supported on the device.
* @throws SecurityException if the caller is not allowed to access security logging, or
diff --git a/core/java/android/app/admin/DevicePolicyResources.java b/core/java/android/app/admin/DevicePolicyResources.java
index a498913..593f736 100644
--- a/core/java/android/app/admin/DevicePolicyResources.java
+++ b/core/java/android/app/admin/DevicePolicyResources.java
@@ -1857,6 +1857,17 @@
public static final String WORK_PROFILE_TELEPHONY_PAUSED_TURN_ON_BUTTON =
PREFIX + "TURN_ON_WORK_PROFILE_BUTTON_TEXT";
+ public static final String MINIRESOLVER_OPEN_IN_WORK =
+ PREFIX + "MINIRESOLVER_OPEN_IN_WORK";
+
+ public static final String MINIRESOLVER_OPEN_IN_PERSONAL =
+ PREFIX + "MINIRESOLVER_OPEN_IN_PERSONAL";
+
+ public static final String MINIRESOLVER_USE_WORK_BROWSER =
+ PREFIX + "MINIRESOLVER_OPEN_IN_PERSONAL";
+
+ public static final String MINIRESOLVER_USE_PERSONAL_BROWSER =
+ PREFIX + "MINIRESOLVER_OPEN_IN_PERSONAL";
}
/**
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 8d508c0..9b0b18a 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -119,7 +119,7 @@
void setRequiredStrongAuthTimeout(in ComponentName who, String callerPackageName, long timeMs, boolean parent);
long getRequiredStrongAuthTimeout(in ComponentName who, int userId, boolean parent);
- void lockNow(int flags, boolean parent);
+ void lockNow(int flags, String callerPackageName, boolean parent);
/**
* @param factoryReset only applicable when `targetSdk >= U`, either tries to factoryReset/fail or removeUser/fail otherwise
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index da6784b..2ca2b79bc 100644
--- a/core/java/android/companion/virtual/VirtualDeviceManager.java
+++ b/core/java/android/companion/virtual/VirtualDeviceManager.java
@@ -64,6 +64,7 @@
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.function.IntConsumer;
@@ -171,6 +172,7 @@
public VirtualDevice createVirtualDevice(
int associationId,
@NonNull VirtualDeviceParams params) {
+ Objects.requireNonNull(params, "params must not be null");
try {
return new VirtualDevice(mService, mContext, associationId, params);
} catch (RemoteException e) {
@@ -409,6 +411,9 @@
@NonNull PendingIntent pendingIntent,
@NonNull Executor executor,
@NonNull IntConsumer listener) {
+ Objects.requireNonNull(pendingIntent, "pendingIntent must not be null");
+ Objects.requireNonNull(executor, "executor must not be null");
+ Objects.requireNonNull(listener, "listener must not be null");
mVirtualDeviceInternal.launchPendingIntent(
displayId, pendingIntent, executor, listener);
}
@@ -483,6 +488,7 @@
@NonNull VirtualDisplayConfig config,
@Nullable @CallbackExecutor Executor executor,
@Nullable VirtualDisplay.Callback callback) {
+ Objects.requireNonNull(config, "config must not be null");
return mVirtualDeviceInternal.createVirtualDisplay(config, executor, callback);
}
@@ -503,6 +509,7 @@
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
@NonNull
public VirtualDpad createVirtualDpad(@NonNull VirtualDpadConfig config) {
+ Objects.requireNonNull(config, "config must not be null");
return mVirtualDeviceInternal.createVirtualDpad(config);
}
@@ -514,6 +521,7 @@
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
@NonNull
public VirtualKeyboard createVirtualKeyboard(@NonNull VirtualKeyboardConfig config) {
+ Objects.requireNonNull(config, "config must not be null");
return mVirtualDeviceInternal.createVirtualKeyboard(config);
}
@@ -550,6 +558,7 @@
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
@NonNull
public VirtualMouse createVirtualMouse(@NonNull VirtualMouseConfig config) {
+ Objects.requireNonNull(config, "config must not be null");
return mVirtualDeviceInternal.createVirtualMouse(config);
}
@@ -587,6 +596,7 @@
@NonNull
public VirtualTouchscreen createVirtualTouchscreen(
@NonNull VirtualTouchscreenConfig config) {
+ Objects.requireNonNull(config, "config must not be null");
return mVirtualDeviceInternal.createVirtualTouchscreen(config);
}
@@ -659,6 +669,7 @@
@NonNull VirtualDisplay display,
@Nullable Executor executor,
@Nullable AudioConfigurationChangeCallback callback) {
+ Objects.requireNonNull(display, "display must not be null");
return mVirtualDeviceInternal.createVirtualAudioDevice(display, executor, callback);
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 58b0571..154068e 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -4233,6 +4233,13 @@
"com.android.intent.action.SHOW_BRIGHTNESS_DIALOG";
/**
+ * Activity Action: Shows the contrast setting dialog.
+ * @hide
+ */
+ public static final String ACTION_SHOW_CONTRAST_DIALOG =
+ "com.android.intent.action.SHOW_CONTRAST_DIALOG";
+
+ /**
* Broadcast Action: A global button was pressed. Includes a single
* extra field, {@link #EXTRA_KEY_EVENT}, containing the key event that
* caused the broadcast.
diff --git a/core/java/android/credentials/CredentialManager.java b/core/java/android/credentials/CredentialManager.java
index 00ce17a..9140d02 100644
--- a/core/java/android/credentials/CredentialManager.java
+++ b/core/java/android/credentials/CredentialManager.java
@@ -460,9 +460,17 @@
return false;
}
+ /**
+ * Returns whether the service is enabled.
+ *
+ * @hide
+ */
private boolean isServiceEnabled() {
- return DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_CREDENTIAL, DEVICE_CONFIG_ENABLE_CREDENTIAL_MANAGER, true);
+ try {
+ return mService.isServiceEnabled();
+ } catch (RemoteException e) {
+ return false;
+ }
}
/**
diff --git a/core/java/android/credentials/ICredentialManager.aidl b/core/java/android/credentials/ICredentialManager.aidl
index 5fde96b..b779c56 100644
--- a/core/java/android/credentials/ICredentialManager.aidl
+++ b/core/java/android/credentials/ICredentialManager.aidl
@@ -58,5 +58,7 @@
List<CredentialProviderInfo> getCredentialProviderServices(in int userId, in int providerFilter);
List<CredentialProviderInfo> getCredentialProviderServicesForTesting(in int providerFilter);
+
+ boolean isServiceEnabled();
}
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index b5281a5..2aead3c 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -1758,10 +1758,12 @@
/**
* Key for the brightness throttling data as a String formatted:
* <displayId>,<no of throttling levels>,[<severity as string>,<brightness cap>]
- * Where the latter part is repeated for each throttling level, and the entirety is repeated
- * for each display, separated by a semicolon.
+ * [,<throttlingId>]?
+ * Where [<severity as string>,<brightness cap>] is repeated for each throttling level.
+ * The entirety is repeated for each display and throttling id, separated by a semicolon.
* For example:
* 123,1,critical,0.8;456,2,moderate,0.9,critical,0.7
+ * 123,1,critical,0.8,default;123,1,moderate,0.6,id_2;456,2,moderate,0.9,critical,0.7
*/
String KEY_BRIGHTNESS_THROTTLING_DATA = "brightness_throttling_data";
}
diff --git a/core/java/android/inputmethodservice/InkWindow.java b/core/java/android/inputmethodservice/InkWindow.java
index 70bd504..15ed450 100644
--- a/core/java/android/inputmethodservice/InkWindow.java
+++ b/core/java/android/inputmethodservice/InkWindow.java
@@ -26,13 +26,17 @@
import android.content.Context;
import android.os.IBinder;
import android.util.Slog;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewRootImpl;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import com.android.internal.policy.PhoneWindow;
+import java.util.Objects;
+
/**
* Window of type {@code LayoutParams.TYPE_INPUT_METHOD_DIALOG} for drawing
* Handwriting Ink on screen.
@@ -185,4 +189,12 @@
return getDecorView().getVisibility() == View.VISIBLE
&& mInkView != null && mInkView.isVisibleToUser();
}
+
+ void dispatchHandwritingEvent(@NonNull MotionEvent event) {
+ final View decor = getDecorView();
+ Objects.requireNonNull(decor);
+ final ViewRootImpl viewRoot = decor.getViewRootImpl();
+ Objects.requireNonNull(viewRoot);
+ viewRoot.enqueueInputEvent(event);
+ }
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index ee9d8a4..a9c4818 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -2563,7 +2563,7 @@
*/
public void onStylusHandwritingMotionEvent(@NonNull MotionEvent motionEvent) {
if (mInkWindow != null && mInkWindow.isInkViewVisible()) {
- mInkWindow.getDecorView().dispatchTouchEvent(motionEvent);
+ mInkWindow.dispatchHandwritingEvent(motionEvent);
} else {
if (mPendingEvents == null) {
mPendingEvents = new RingBuffer(MotionEvent.class, MAX_EVENTS_BUFFER);
@@ -2576,7 +2576,7 @@
if (mInkWindow == null) {
break;
}
- mInkWindow.getDecorView().dispatchTouchEvent(event);
+ mInkWindow.dispatchHandwritingEvent(event);
}
mPendingEvents.clear();
}
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 5c2b389..402da28 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -1008,9 +1008,8 @@
.allowAlarms(allowAlarms)
.allowMedia(allowMedia)
.allowSystem(allowSystem)
- .allowConversations(allowConversations
- ? ZenModeConfig.getZenPolicySenders(allowConversationsFrom)
- : ZenPolicy.PEOPLE_TYPE_NONE);
+ .allowConversations(allowConversations ? allowConversationsFrom
+ : ZenPolicy.CONVERSATION_SENDERS_NONE);
if (suppressedVisualEffects == 0) {
builder.showAllVisualEffects();
} else {
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
index eb467e0..992a586 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
@@ -75,6 +75,11 @@
private static final int APK_SIGNATURE_SCHEME_V2_BLOCK_ID = 0x7109871a;
/**
+ * The maximum number of signers supported by the v2 APK signature scheme.
+ */
+ private static final int MAX_V2_SIGNERS = 10;
+
+ /**
* Returns {@code true} if the provided APK contains an APK Signature Scheme V2 signature.
*
* <p><b>NOTE: This method does not verify the signature.</b>
@@ -183,6 +188,11 @@
}
while (signers.hasRemaining()) {
signerCount++;
+ if (signerCount > MAX_V2_SIGNERS) {
+ throw new SecurityException(
+ "APK Signature Scheme v2 only supports a maximum of " + MAX_V2_SIGNERS
+ + " signers");
+ }
try {
ByteBuffer signer = getLengthPrefixedSlice(signers);
X509Certificate[] certs = verifySigner(signer, contentDigests, certFactory);
diff --git a/core/java/android/util/jar/StrictJarVerifier.java b/core/java/android/util/jar/StrictJarVerifier.java
index 4525490..a6aca33 100644
--- a/core/java/android/util/jar/StrictJarVerifier.java
+++ b/core/java/android/util/jar/StrictJarVerifier.java
@@ -78,6 +78,11 @@
"SHA1",
};
+ /**
+ * The maximum number of signers supported by the JAR signature scheme.
+ */
+ private static final int MAX_JAR_SIGNERS = 10;
+
private final String jarName;
private final StrictJarManifest manifest;
private final HashMap<String, byte[]> metaEntries;
@@ -293,10 +298,16 @@
return false;
}
+ int signerCount = 0;
Iterator<String> it = metaEntries.keySet().iterator();
while (it.hasNext()) {
String key = it.next();
if (key.endsWith(".DSA") || key.endsWith(".RSA") || key.endsWith(".EC")) {
+ if (++signerCount > MAX_JAR_SIGNERS) {
+ throw new SecurityException(
+ "APK Signature Scheme v1 only supports a maximum of " + MAX_JAR_SIGNERS
+ + " signers");
+ }
verifyCertificate(key);
it.remove();
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 152fa08..2f5cd54 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -265,6 +265,7 @@
private static final boolean DEBUG_KEEP_SCREEN_ON = false || LOCAL_LOGV;
private static final boolean DEBUG_CONTENT_CAPTURE = false || LOCAL_LOGV;
private static final boolean DEBUG_SCROLL_CAPTURE = false || LOCAL_LOGV;
+ private static final boolean DEBUG_TOUCH_NAVIGATION = false || LOCAL_LOGV;
private static final boolean DEBUG_BLAST = false || LOCAL_LOGV;
private static final int LOGTAG_INPUT_FOCUS = 62001;
@@ -7122,7 +7123,8 @@
mJoystick.cancel();
} else if ((source & InputDevice.SOURCE_TOUCH_NAVIGATION)
== InputDevice.SOURCE_TOUCH_NAVIGATION) {
- mTouchNavigation.cancel(event);
+ // Touch navigation events cannot be cancelled since they are dispatched
+ // immediately.
}
}
}
@@ -7641,392 +7643,109 @@
}
/**
- * Creates dpad events from unhandled touch navigation movements.
+ * Creates DPAD events from unhandled touch navigation movements.
*/
final class SyntheticTouchNavigationHandler extends Handler {
private static final String LOCAL_TAG = "SyntheticTouchNavigationHandler";
- private static final boolean LOCAL_DEBUG = false;
- // Assumed nominal width and height in millimeters of a touch navigation pad,
- // if no resolution information is available from the input system.
- private static final float DEFAULT_WIDTH_MILLIMETERS = 48;
- private static final float DEFAULT_HEIGHT_MILLIMETERS = 48;
-
- /* TODO: These constants should eventually be moved to ViewConfiguration. */
-
- // The nominal distance traveled to move by one unit.
- private static final int TICK_DISTANCE_MILLIMETERS = 12;
-
- // Minimum and maximum fling velocity in ticks per second.
- // The minimum velocity should be set such that we perform enough ticks per
- // second that the fling appears to be fluid. For example, if we set the minimum
- // to 2 ticks per second, then there may be up to half a second delay between the next
- // to last and last ticks which is noticeably discrete and jerky. This value should
- // probably not be set to anything less than about 4.
- // If fling accuracy is a problem then consider tuning the tick distance instead.
- private static final float MIN_FLING_VELOCITY_TICKS_PER_SECOND = 6f;
- private static final float MAX_FLING_VELOCITY_TICKS_PER_SECOND = 20f;
-
- // Fling velocity decay factor applied after each new key is emitted.
- // This parameter controls the deceleration and overall duration of the fling.
- // The fling stops automatically when its velocity drops below the minimum
- // fling velocity defined above.
- private static final float FLING_TICK_DECAY = 0.8f;
-
- /* The input device that we are tracking. */
-
+ // The id of the input device that is being tracked.
private int mCurrentDeviceId = -1;
private int mCurrentSource;
- private boolean mCurrentDeviceSupported;
- /* Configuration for the current input device. */
-
- // The scaled tick distance. A movement of this amount should generally translate
- // into a single dpad event in a given direction.
- private float mConfigTickDistance;
-
- // The minimum and maximum scaled fling velocity.
- private float mConfigMinFlingVelocity;
- private float mConfigMaxFlingVelocity;
-
- /* Tracking state. */
-
- // The velocity tracker for detecting flings.
- private VelocityTracker mVelocityTracker;
-
- // The active pointer id, or -1 if none.
- private int mActivePointerId = -1;
-
- // Location where tracking started.
- private float mStartX;
- private float mStartY;
-
- // Most recently observed position.
- private float mLastX;
- private float mLastY;
-
- // Accumulated movement delta since the last direction key was sent.
- private float mAccumulatedX;
- private float mAccumulatedY;
-
- // Set to true if any movement was delivered to the app.
- // Implies that tap slop was exceeded.
- private boolean mConsumedMovement;
-
- // The most recently sent key down event.
- // The keycode remains set until the direction changes or a fling ends
- // so that repeated key events may be generated as required.
- private long mPendingKeyDownTime;
- private int mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
- private int mPendingKeyRepeatCount;
private int mPendingKeyMetaState;
- // The current fling velocity while a fling is in progress.
- private boolean mFlinging;
- private float mFlingVelocity;
+ private final GestureDetector mGestureDetector = new GestureDetector(mContext,
+ new GestureDetector.OnGestureListener() {
+ @Override
+ public boolean onDown(@NonNull MotionEvent e) {
+ // This can be ignored since it's not clear what KeyEvent this will
+ // belong to.
+ return true;
+ }
- public SyntheticTouchNavigationHandler() {
+ @Override
+ public void onShowPress(@NonNull MotionEvent e) {
+
+ }
+
+ @Override
+ public boolean onSingleTapUp(@NonNull MotionEvent e) {
+ dispatchTap(e.getEventTime());
+ return true;
+ }
+
+ @Override
+ public boolean onScroll(@Nullable MotionEvent e1, @NonNull MotionEvent e2,
+ float distanceX, float distanceY) {
+ // Scroll doesn't translate to DPAD events so should be ignored.
+ return true;
+ }
+
+ @Override
+ public void onLongPress(@NonNull MotionEvent e) {
+ // Long presses don't translate to DPAD events so should be ignored.
+ }
+
+ @Override
+ public boolean onFling(@Nullable MotionEvent e1, @NonNull MotionEvent e2,
+ float velocityX, float velocityY) {
+ dispatchFling(velocityX, velocityY, e2.getEventTime());
+ return true;
+ }
+ });
+
+ SyntheticTouchNavigationHandler() {
super(true);
}
public void process(MotionEvent event) {
+ if (event.getDevice() == null) {
+ // The current device is not supported.
+ if (DEBUG_TOUCH_NAVIGATION) {
+ Log.d(LOCAL_TAG,
+ "Current device not supported so motion event is not processed");
+ }
+ return;
+ }
+ mPendingKeyMetaState = event.getMetaState();
// Update the current device information.
- final long time = event.getEventTime();
final int deviceId = event.getDeviceId();
final int source = event.getSource();
if (mCurrentDeviceId != deviceId || mCurrentSource != source) {
- finishKeys(time);
- finishTracking(time);
mCurrentDeviceId = deviceId;
mCurrentSource = source;
- mCurrentDeviceSupported = false;
- InputDevice device = event.getDevice();
- if (device != null) {
- // In order to support an input device, we must know certain
- // characteristics about it, such as its size and resolution.
- InputDevice.MotionRange xRange = device.getMotionRange(MotionEvent.AXIS_X);
- InputDevice.MotionRange yRange = device.getMotionRange(MotionEvent.AXIS_Y);
- if (xRange != null && yRange != null) {
- mCurrentDeviceSupported = true;
-
- // Infer the resolution if it not actually known.
- float xRes = xRange.getResolution();
- if (xRes <= 0) {
- xRes = xRange.getRange() / DEFAULT_WIDTH_MILLIMETERS;
- }
- float yRes = yRange.getResolution();
- if (yRes <= 0) {
- yRes = yRange.getRange() / DEFAULT_HEIGHT_MILLIMETERS;
- }
- float nominalRes = (xRes + yRes) * 0.5f;
-
- // Precompute all of the configuration thresholds we will need.
- mConfigTickDistance = TICK_DISTANCE_MILLIMETERS * nominalRes;
- mConfigMinFlingVelocity =
- MIN_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
- mConfigMaxFlingVelocity =
- MAX_FLING_VELOCITY_TICKS_PER_SECOND * mConfigTickDistance;
-
- if (LOCAL_DEBUG) {
- Log.d(LOCAL_TAG, "Configured device " + mCurrentDeviceId
- + " (" + Integer.toHexString(mCurrentSource) + "): "
- + ", mConfigTickDistance=" + mConfigTickDistance
- + ", mConfigMinFlingVelocity=" + mConfigMinFlingVelocity
- + ", mConfigMaxFlingVelocity=" + mConfigMaxFlingVelocity);
- }
- }
- }
- }
- if (!mCurrentDeviceSupported) {
- return;
}
- // Handle the event.
- final int action = event.getActionMasked();
- switch (action) {
- case MotionEvent.ACTION_DOWN: {
- boolean caughtFling = mFlinging;
- finishKeys(time);
- finishTracking(time);
- mActivePointerId = event.getPointerId(0);
- mVelocityTracker = VelocityTracker.obtain();
- mVelocityTracker.addMovement(event);
- mStartX = event.getX();
- mStartY = event.getY();
- mLastX = mStartX;
- mLastY = mStartY;
- mAccumulatedX = 0;
- mAccumulatedY = 0;
-
- // If we caught a fling, then pretend that the tap slop has already
- // been exceeded to suppress taps whose only purpose is to stop the fling.
- mConsumedMovement = caughtFling;
- break;
- }
-
- case MotionEvent.ACTION_MOVE:
- case MotionEvent.ACTION_UP: {
- if (mActivePointerId < 0) {
- break;
- }
- final int index = event.findPointerIndex(mActivePointerId);
- if (index < 0) {
- finishKeys(time);
- finishTracking(time);
- break;
- }
-
- mVelocityTracker.addMovement(event);
- final float x = event.getX(index);
- final float y = event.getY(index);
- mAccumulatedX += x - mLastX;
- mAccumulatedY += y - mLastY;
- mLastX = x;
- mLastY = y;
-
- // Consume any accumulated movement so far.
- final int metaState = event.getMetaState();
- consumeAccumulatedMovement(time, metaState);
-
- // Detect taps and flings.
- if (action == MotionEvent.ACTION_UP) {
- if (mConsumedMovement && mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
- // It might be a fling.
- mVelocityTracker.computeCurrentVelocity(1000, mConfigMaxFlingVelocity);
- final float vx = mVelocityTracker.getXVelocity(mActivePointerId);
- final float vy = mVelocityTracker.getYVelocity(mActivePointerId);
- if (!startFling(time, vx, vy)) {
- finishKeys(time);
- }
- }
- finishTracking(time);
- }
- break;
- }
-
- case MotionEvent.ACTION_CANCEL: {
- finishKeys(time);
- finishTracking(time);
- break;
- }
- }
+ // Interpret the event.
+ mGestureDetector.onTouchEvent(event);
}
- public void cancel(MotionEvent event) {
- if (mCurrentDeviceId == event.getDeviceId()
- && mCurrentSource == event.getSource()) {
- final long time = event.getEventTime();
- finishKeys(time);
- finishTracking(time);
- }
+ private void dispatchTap(long time) {
+ dispatchEvent(time, KeyEvent.KEYCODE_DPAD_CENTER);
}
- private void finishKeys(long time) {
- cancelFling();
- sendKeyUp(time);
- }
-
- private void finishTracking(long time) {
- if (mActivePointerId >= 0) {
- mActivePointerId = -1;
- mVelocityTracker.recycle();
- mVelocityTracker = null;
- }
- }
-
- private void consumeAccumulatedMovement(long time, int metaState) {
- final float absX = Math.abs(mAccumulatedX);
- final float absY = Math.abs(mAccumulatedY);
- if (absX >= absY) {
- if (absX >= mConfigTickDistance) {
- mAccumulatedX = consumeAccumulatedMovement(time, metaState, mAccumulatedX,
- KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_RIGHT);
- mAccumulatedY = 0;
- mConsumedMovement = true;
- }
+ private void dispatchFling(float x, float y, long time) {
+ if (Math.abs(x) > Math.abs(y)) {
+ dispatchEvent(time,
+ x > 0 ? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT);
} else {
- if (absY >= mConfigTickDistance) {
- mAccumulatedY = consumeAccumulatedMovement(time, metaState, mAccumulatedY,
- KeyEvent.KEYCODE_DPAD_UP, KeyEvent.KEYCODE_DPAD_DOWN);
- mAccumulatedX = 0;
- mConsumedMovement = true;
- }
+ dispatchEvent(time, y > 0 ? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP);
}
}
- private float consumeAccumulatedMovement(long time, int metaState,
- float accumulator, int negativeKeyCode, int positiveKeyCode) {
- while (accumulator <= -mConfigTickDistance) {
- sendKeyDownOrRepeat(time, negativeKeyCode, metaState);
- accumulator += mConfigTickDistance;
+ private void dispatchEvent(long time, int keyCode) {
+ if (DEBUG_TOUCH_NAVIGATION) {
+ Log.d(LOCAL_TAG, "Dispatching DPAD events DOWN and UP with keycode " + keyCode);
}
- while (accumulator >= mConfigTickDistance) {
- sendKeyDownOrRepeat(time, positiveKeyCode, metaState);
- accumulator -= mConfigTickDistance;
- }
- return accumulator;
+ enqueueInputEvent(new KeyEvent(time, time,
+ KeyEvent.ACTION_DOWN, keyCode, /* repeat= */ 0, mPendingKeyMetaState,
+ mCurrentDeviceId, /* scancode= */ 0, KeyEvent.FLAG_FALLBACK,
+ mCurrentSource));
+ enqueueInputEvent(new KeyEvent(time, time,
+ KeyEvent.ACTION_UP, keyCode, /* repeat= */ 0, mPendingKeyMetaState,
+ mCurrentDeviceId, /* scancode= */ 0, KeyEvent.FLAG_FALLBACK,
+ mCurrentSource));
}
-
- private void sendKeyDownOrRepeat(long time, int keyCode, int metaState) {
- if (mPendingKeyCode != keyCode) {
- sendKeyUp(time);
- mPendingKeyDownTime = time;
- mPendingKeyCode = keyCode;
- mPendingKeyRepeatCount = 0;
- } else {
- mPendingKeyRepeatCount += 1;
- }
- mPendingKeyMetaState = metaState;
-
- // Note: Normally we would pass FLAG_LONG_PRESS when the repeat count is 1
- // but it doesn't quite make sense when simulating the events in this way.
- if (LOCAL_DEBUG) {
- Log.d(LOCAL_TAG, "Sending key down: keyCode=" + mPendingKeyCode
- + ", repeatCount=" + mPendingKeyRepeatCount
- + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
- }
- enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
- KeyEvent.ACTION_DOWN, mPendingKeyCode, mPendingKeyRepeatCount,
- mPendingKeyMetaState, mCurrentDeviceId,
- KeyEvent.FLAG_FALLBACK, mCurrentSource));
- }
-
- private void sendKeyUp(long time) {
- if (mPendingKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
- if (LOCAL_DEBUG) {
- Log.d(LOCAL_TAG, "Sending key up: keyCode=" + mPendingKeyCode
- + ", metaState=" + Integer.toHexString(mPendingKeyMetaState));
- }
- enqueueInputEvent(new KeyEvent(mPendingKeyDownTime, time,
- KeyEvent.ACTION_UP, mPendingKeyCode, 0, mPendingKeyMetaState,
- mCurrentDeviceId, 0, KeyEvent.FLAG_FALLBACK,
- mCurrentSource));
- mPendingKeyCode = KeyEvent.KEYCODE_UNKNOWN;
- }
- }
-
- private boolean startFling(long time, float vx, float vy) {
- if (LOCAL_DEBUG) {
- Log.d(LOCAL_TAG, "Considering fling: vx=" + vx + ", vy=" + vy
- + ", min=" + mConfigMinFlingVelocity);
- }
-
- // Flings must be oriented in the same direction as the preceding movements.
- switch (mPendingKeyCode) {
- case KeyEvent.KEYCODE_DPAD_LEFT:
- if (-vx >= mConfigMinFlingVelocity
- && Math.abs(vy) < mConfigMinFlingVelocity) {
- mFlingVelocity = -vx;
- break;
- }
- return false;
-
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- if (vx >= mConfigMinFlingVelocity
- && Math.abs(vy) < mConfigMinFlingVelocity) {
- mFlingVelocity = vx;
- break;
- }
- return false;
-
- case KeyEvent.KEYCODE_DPAD_UP:
- if (-vy >= mConfigMinFlingVelocity
- && Math.abs(vx) < mConfigMinFlingVelocity) {
- mFlingVelocity = -vy;
- break;
- }
- return false;
-
- case KeyEvent.KEYCODE_DPAD_DOWN:
- if (vy >= mConfigMinFlingVelocity
- && Math.abs(vx) < mConfigMinFlingVelocity) {
- mFlingVelocity = vy;
- break;
- }
- return false;
- }
-
- // Post the first fling event.
- mFlinging = postFling(time);
- return mFlinging;
- }
-
- private boolean postFling(long time) {
- // The idea here is to estimate the time when the pointer would have
- // traveled one tick distance unit given the current fling velocity.
- // This effect creates continuity of motion.
- if (mFlingVelocity >= mConfigMinFlingVelocity) {
- long delay = (long)(mConfigTickDistance / mFlingVelocity * 1000);
- postAtTime(mFlingRunnable, time + delay);
- if (LOCAL_DEBUG) {
- Log.d(LOCAL_TAG, "Posted fling: velocity="
- + mFlingVelocity + ", delay=" + delay
- + ", keyCode=" + mPendingKeyCode);
- }
- return true;
- }
- return false;
- }
-
- private void cancelFling() {
- if (mFlinging) {
- removeCallbacks(mFlingRunnable);
- mFlinging = false;
- }
- }
-
- private final Runnable mFlingRunnable = new Runnable() {
- @Override
- public void run() {
- final long time = SystemClock.uptimeMillis();
- sendKeyDownOrRepeat(time, mPendingKeyCode, mPendingKeyMetaState);
- mFlingVelocity *= FLING_TICK_DECAY;
- if (!postFling(time)) {
- mFlinging = false;
- finishKeys(time);
- }
- }
- };
}
final class SyntheticKeyboardHandler {
@@ -9272,7 +8991,7 @@
}
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- void enqueueInputEvent(InputEvent event) {
+ public void enqueueInputEvent(InputEvent event) {
enqueueInputEvent(event, null, 0, false);
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 48686fc..02b3478 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -869,6 +869,42 @@
"android.window.PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION";
/**
+ * Application level {@link android.content.pm.PackageManager.Property PackageManager.Property}
+ * for an app to inform the system that the app can be opted-out from the compatibility
+ * treatment that avoids {@link android.app.Activity#setRequestedOrientation} loops. The loop
+ * can be trigerred by ignoreRequestedOrientation display setting enabled on the device or
+ * by the landscape natural orientation of the device.
+ *
+ * <p>The system could ignore {@link android.app.Activity#setRequestedOrientation}
+ * call from an app if both of the following conditions are true:
+ * <ul>
+ * <li>Activity has requested orientation more than 2 times within 1-second timer
+ * <li>Activity is not letterboxed for fixed orientation
+ * </ul>
+ *
+ * <p>Setting this property to {@code false} informs the system that the app must be
+ * opted-out from the compatibility treatment even if the device manufacturer has opted the app
+ * into the treatment.
+ *
+ * <p>Not setting this property at all, or setting this property to {@code true} has no effect.
+ *
+ * <p><b>Syntax:</b>
+ * <pre>
+ * <application>
+ * <property
+ * android:name=
+ * "android.window.PROPERTY_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED"
+ * android:value="false"/>
+ * </application>
+ * </pre>
+ *
+ * @hide
+ */
+ // TODO(b/274924641): Make this public API.
+ String PROPERTY_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED =
+ "android.window.PROPERTY_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED";
+
+ /**
* Application level {@link android.content.pm.PackageManager.Property PackageManager
* .Property} for an app to inform the system that it needs to be opted-out from the
* compatibility treatment that sandboxes {@link android.view.View} API.
diff --git a/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java b/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java
index ec50c69..aa9225b 100644
--- a/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java
+++ b/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java
@@ -418,12 +418,15 @@
});
}
+ @Dispatching(cancellable = false)
@Override
public void cancelCancellationSignal(IBinder token) {
if (mBeamer == null) {
return;
}
- mBeamer.cancel(token);
+ dispatch(() -> {
+ mBeamer.cancel(token);
+ });
}
@Override
diff --git a/core/java/android/window/ScreenCapture.java b/core/java/android/window/ScreenCapture.java
index d8e64d4..95451a9 100644
--- a/core/java/android/window/ScreenCapture.java
+++ b/core/java/android/window/ScreenCapture.java
@@ -309,7 +309,7 @@
/** Release any layers if set using {@link Builder#setExcludeLayers(SurfaceControl[])}. */
public void release() {
- if (mExcludeLayers.length == 0) {
+ if (mExcludeLayers == null || mExcludeLayers.length == 0) {
return;
}
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index 75e797b..44d517a 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -19,6 +19,7 @@
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.app.admin.DevicePolicyResources.Strings.Core.FORWARD_INTENT_TO_PERSONAL;
import static android.app.admin.DevicePolicyResources.Strings.Core.FORWARD_INTENT_TO_WORK;
+import static android.app.admin.DevicePolicyResources.Strings.Core.MINIRESOLVER_OPEN_IN_WORK;
import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -212,9 +213,7 @@
buttonContainer.setPadding(0, 0, 0, buttonContainer.getPaddingBottom());
((TextView) findViewById(R.id.open_cross_profile)).setText(
- getResources().getString(
- R.string.miniresolver_open_in_work,
- target.loadLabel(packageManagerForTargetUser)));
+ getOpenInWorkMessage(target.loadLabel(packageManagerForTargetUser)));
// The mini-resolver's negative button is reused in this flow to cancel the intent
((Button) findViewById(R.id.use_same_profile_browser)).setText(R.string.cancel);
@@ -226,6 +225,13 @@
});
}
+ private String getOpenInWorkMessage(CharSequence targetLabel) {
+ return getSystemService(DevicePolicyManager.class).getResources().getString(
+ MINIRESOLVER_OPEN_IN_WORK,
+ () -> getString(R.string.miniresolver_open_in_work, targetLabel),
+ targetLabel);
+ }
+
private String getForwardToPersonalMessage() {
return getSystemService(DevicePolicyManager.class).getResources().getString(
FORWARD_INTENT_TO_PERSONAL,
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 73c5207..499d38c 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -19,6 +19,10 @@
import static android.Manifest.permission.INTERACT_ACROSS_PROFILES;
import static android.app.admin.DevicePolicyResources.Strings.Core.FORWARD_INTENT_TO_PERSONAL;
import static android.app.admin.DevicePolicyResources.Strings.Core.FORWARD_INTENT_TO_WORK;
+import static android.app.admin.DevicePolicyResources.Strings.Core.MINIRESOLVER_OPEN_IN_PERSONAL;
+import static android.app.admin.DevicePolicyResources.Strings.Core.MINIRESOLVER_OPEN_IN_WORK;
+import static android.app.admin.DevicePolicyResources.Strings.Core.MINIRESOLVER_USE_PERSONAL_BROWSER;
+import static android.app.admin.DevicePolicyResources.Strings.Core.MINIRESOLVER_USE_WORK_BROWSER;
import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_ACCESS_PERSONAL;
import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_ACCESS_WORK;
import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CROSS_PROFILE_BLOCKED_TITLE;
@@ -46,6 +50,7 @@
import android.app.VoiceInteractor.Prompt;
import android.app.admin.DevicePolicyEventLogger;
import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyResourcesManager;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -1713,14 +1718,29 @@
}
}.execute();
- ((TextView) findViewById(R.id.open_cross_profile)).setText(
- getResources().getString(
- inWorkProfile ? R.string.miniresolver_open_in_personal
- : R.string.miniresolver_open_in_work,
- otherProfileResolveInfo.getDisplayLabel()));
- ((Button) findViewById(R.id.use_same_profile_browser)).setText(
- inWorkProfile ? R.string.miniresolver_use_work_browser
- : R.string.miniresolver_use_personal_browser);
+ CharSequence targetDisplayLabel = otherProfileResolveInfo.getDisplayLabel();
+
+ DevicePolicyResourcesManager devicePolicyResourcesManager = getSystemService(
+ DevicePolicyManager.class).getResources();
+
+ if (inWorkProfile) {
+ ((TextView) findViewById(R.id.open_cross_profile)).setText(
+ devicePolicyResourcesManager.getString(MINIRESOLVER_OPEN_IN_WORK,
+ () -> getString(R.string.miniresolver_open_in_work, targetDisplayLabel),
+ targetDisplayLabel));
+ ((Button) findViewById(R.id.use_same_profile_browser)).setText(
+ devicePolicyResourcesManager.getString(MINIRESOLVER_USE_WORK_BROWSER,
+ () -> getString(R.string.miniresolver_use_work_browser)));
+ } else {
+ ((TextView) findViewById(R.id.open_cross_profile)).setText(
+ devicePolicyResourcesManager.getString(MINIRESOLVER_OPEN_IN_PERSONAL,
+ () -> getString(R.string.miniresolver_open_in_personal,
+ targetDisplayLabel),
+ targetDisplayLabel));
+ ((Button) findViewById(R.id.use_same_profile_browser)).setText(
+ devicePolicyResourcesManager.getString(MINIRESOLVER_USE_PERSONAL_BROWSER,
+ () -> getString(R.string.miniresolver_use_personal_browser)));
+ }
findViewById(R.id.use_same_profile_browser).setOnClickListener(
v -> {
diff --git a/core/java/com/android/internal/widget/MessagingImageMessage.java b/core/java/com/android/internal/widget/MessagingImageMessage.java
index 8e7fe18..098bce1 100644
--- a/core/java/com/android/internal/widget/MessagingImageMessage.java
+++ b/core/java/com/android/internal/widget/MessagingImageMessage.java
@@ -198,6 +198,11 @@
@Override
public int getMeasuredType() {
+ if (mDrawable == null) {
+ Log.e(TAG, "getMeasuredType() after recycle()!");
+ return MEASURED_NORMAL;
+ }
+
int measuredHeight = getMeasuredHeight();
int minImageHeight;
if (mIsIsolated) {
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 76bae8de..3ff6351 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4461,7 +4461,8 @@
See android.credentials.CredentialManager
-->
- <string name="config_defaultCredentialProviderService" translatable="false"></string>
+ <string-array name="config_defaultCredentialProviderService" translatable="false">
+ </string-array>
<!-- The package name for the system's smartspace service.
This service returns smartspace results.
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 9fc2ed1..7b582da 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3754,7 +3754,7 @@
<java-symbol type="string" name="config_defaultAppPredictionService" />
<java-symbol type="string" name="config_defaultContentSuggestionsService" />
<java-symbol type="string" name="config_defaultCredentialManagerHybridService" />
- <java-symbol type="string" name="config_defaultCredentialProviderService" />
+ <java-symbol type="array" name="config_defaultCredentialProviderService" />
<java-symbol type="string" name="config_defaultSearchUiService" />
<java-symbol type="string" name="config_defaultSmartspaceService" />
<java-symbol type="string" name="config_defaultWallpaperEffectsGenerationService" />
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index a64bb21..e59b259 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -4034,47 +4034,47 @@
<item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
<item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
<item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
<item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
<item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
+ <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
<item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
<item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
- <item name="materialColorErrorContainer">@color/system_error_container_dark</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorErrorContainer">@color/system_error_container_light</item>
<item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
+ <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
<item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+ <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
<item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
- <item name="materialColorOnBackground">@color/system_on_background_dark</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorOnBackground">@color/system_on_background_light</item>
<item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
- <item name="materialColorSecondary">@color/system_secondary_dark</item>
- <item name="materialColorOnError">@color/system_on_error_dark</item>
- <item name="materialColorSurface">@color/system_surface_dark</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
- <item name="materialColorTertiary">@color/system_tertiary_dark</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
- <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
- <item name="materialColorOutline">@color/system_outline_dark</item>
- <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
- <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorOnError">@color/system_on_error_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorTertiary">@color/system_tertiary_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOutline">@color/system_outline_light</item>
+ <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
</style>
@@ -4114,47 +4114,47 @@
<item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
<item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
<item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
<item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
<item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
+ <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
<item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
<item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
- <item name="materialColorErrorContainer">@color/system_error_container_dark</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorErrorContainer">@color/system_error_container_light</item>
<item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
+ <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
<item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+ <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
<item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
- <item name="materialColorOnBackground">@color/system_on_background_dark</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorOnBackground">@color/system_on_background_light</item>
<item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
- <item name="materialColorSecondary">@color/system_secondary_dark</item>
- <item name="materialColorOnError">@color/system_on_error_dark</item>
- <item name="materialColorSurface">@color/system_surface_dark</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
- <item name="materialColorTertiary">@color/system_tertiary_dark</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
- <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
- <item name="materialColorOutline">@color/system_outline_dark</item>
- <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
- <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorOnError">@color/system_on_error_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorTertiary">@color/system_tertiary_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOutline">@color/system_outline_light</item>
+ <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
</style>
@@ -4186,47 +4186,47 @@
<item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
<item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
<item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
<item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
<item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
+ <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
<item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
<item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
- <item name="materialColorErrorContainer">@color/system_error_container_dark</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorErrorContainer">@color/system_error_container_light</item>
<item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
+ <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
<item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+ <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
<item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
- <item name="materialColorOnBackground">@color/system_on_background_dark</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorOnBackground">@color/system_on_background_light</item>
<item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
- <item name="materialColorSecondary">@color/system_secondary_dark</item>
- <item name="materialColorOnError">@color/system_on_error_dark</item>
- <item name="materialColorSurface">@color/system_surface_dark</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
- <item name="materialColorTertiary">@color/system_tertiary_dark</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
- <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
- <item name="materialColorOutline">@color/system_outline_dark</item>
- <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
- <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorOnError">@color/system_on_error_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorTertiary">@color/system_tertiary_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOutline">@color/system_outline_light</item>
+ <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
</style>
@@ -4357,47 +4357,47 @@
<item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
<item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
- <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
+ <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
<item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
- <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
- <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
- <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
- <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
+ <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
+ <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
+ <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
+ <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
<item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
- <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
+ <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
<item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
- <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item>
+ <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item>
<item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
<item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
<item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
- <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
- <item name="materialColorErrorContainer">@color/system_error_container_dark</item>
+ <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
+ <item name="materialColorErrorContainer">@color/system_error_container_light</item>
<item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
- <item name="materialColorPrimaryInverse">@color/system_primary_dark</item>
+ <item name="materialColorPrimaryInverse">@color/system_primary_light</item>
<item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
- <item name="materialColorSurfaceInverse">@color/system_surface_dark</item>
- <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
- <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
+ <item name="materialColorSurfaceInverse">@color/system_surface_light</item>
+ <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
+ <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
<item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
- <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
- <item name="materialColorOnBackground">@color/system_on_background_dark</item>
+ <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
+ <item name="materialColorOnBackground">@color/system_on_background_light</item>
<item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
- <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
- <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
- <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
- <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
- <item name="materialColorSecondary">@color/system_secondary_dark</item>
- <item name="materialColorOnError">@color/system_on_error_dark</item>
- <item name="materialColorSurface">@color/system_surface_dark</item>
- <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
- <item name="materialColorTertiary">@color/system_tertiary_dark</item>
- <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
- <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
- <item name="materialColorOutline">@color/system_outline_dark</item>
- <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
- <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
- <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
- <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
+ <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
+ <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
+ <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
+ <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
+ <item name="materialColorSecondary">@color/system_secondary_light</item>
+ <item name="materialColorOnError">@color/system_on_error_light</item>
+ <item name="materialColorSurface">@color/system_surface_light</item>
+ <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
+ <item name="materialColorTertiary">@color/system_tertiary_light</item>
+ <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
+ <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
+ <item name="materialColorOutline">@color/system_outline_light</item>
+ <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
+ <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
+ <item name="materialColorOnSurface">@color/system_on_surface_light</item>
+ <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
</style>
diff --git a/core/tests/coretests/src/android/provider/DeviceConfigServiceManagerTest.java b/core/tests/coretests/src/android/provider/DeviceConfigServiceManagerTest.java
new file mode 100644
index 0000000..e20258a
--- /dev/null
+++ b/core/tests/coretests/src/android/provider/DeviceConfigServiceManagerTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.provider;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeTrue;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Class that tests the APIs of DeviceConfigServiceManager.ServiceRegisterer.
+ */
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class DeviceConfigServiceManagerTest {
+
+ private static final String SERVICE_NAME = "device_config_updatable";
+ private DeviceConfigServiceManager.ServiceRegisterer mRegisterer;
+
+ @Before
+ public void setUp() {
+ mRegisterer = new DeviceConfigServiceManager.ServiceRegisterer(SERVICE_NAME);
+ }
+
+ @Test
+ public void testGetOrThrow() throws DeviceConfigServiceManager.ServiceNotFoundException {
+ if (UpdatableDeviceConfigServiceReadiness.shouldStartUpdatableService()) {
+ assertThat(mRegisterer.getOrThrow()).isNotNull();
+ } else {
+ assertThrows(DeviceConfigServiceManager.ServiceNotFoundException.class,
+ mRegisterer::getOrThrow);
+ }
+ }
+
+ @Test
+ public void testGet() {
+ assumeTrue(UpdatableDeviceConfigServiceReadiness.shouldStartUpdatableService());
+ assertThat(mRegisterer.get()).isNotNull();
+ }
+
+ @Test
+ public void testTryGet() {
+ if (UpdatableDeviceConfigServiceReadiness.shouldStartUpdatableService()) {
+ assertThat(mRegisterer.tryGet()).isNotNull();
+ } else {
+ assertThat(mRegisterer.tryGet()).isNull();
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
index d18e98a..248a5fc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
@@ -18,6 +18,8 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.app.ActivityManager;
import android.content.Context;
@@ -146,6 +148,13 @@
t.setScale(sc, currentScaleX, currentScaleY);
t.apply();
});
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mTransitions.getMainExecutor().execute(
+ () -> finishCallback.onTransitionFinished(null, null));
+ }
+ });
animator.start();
return true;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index e08d40d..efc90b5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -91,6 +91,16 @@
private Drawable mAppIcon;
private CharSequence mAppName;
+ private int mMenuWidth;
+ private int mMarginMenuTop;
+ private int mMarginMenuStart;
+ private int mMarginMenuSpacing;
+ private int mAppInfoPillHeight;
+ private int mWindowingPillHeight;
+ private int mMoreActionsPillHeight;
+ private int mShadowRadius;
+ private int mCornerRadius;
+
DesktopModeWindowDecoration(
Context context,
DisplayController displayController,
@@ -107,6 +117,29 @@
mSyncQueue = syncQueue;
loadAppInfo();
+ loadHandleMenuDimensions();
+ }
+
+ private void loadHandleMenuDimensions() {
+ final Resources resources = mDecorWindowContext.getResources();
+ mMenuWidth = loadDimensionPixelSize(resources,
+ R.dimen.desktop_mode_handle_menu_width);
+ mMarginMenuTop = loadDimensionPixelSize(resources,
+ R.dimen.desktop_mode_handle_menu_margin_top);
+ mMarginMenuStart = loadDimensionPixelSize(resources,
+ R.dimen.desktop_mode_handle_menu_margin_start);
+ mMarginMenuSpacing = loadDimensionPixelSize(resources,
+ R.dimen.desktop_mode_handle_menu_pill_spacing_margin);
+ mAppInfoPillHeight = loadDimensionPixelSize(resources,
+ R.dimen.desktop_mode_handle_menu_app_info_pill_height);
+ mWindowingPillHeight = loadDimensionPixelSize(resources,
+ R.dimen.desktop_mode_handle_menu_windowing_pill_height);
+ mShadowRadius = loadDimensionPixelSize(resources,
+ R.dimen.desktop_mode_handle_menu_shadow_radius);
+ mCornerRadius = loadDimensionPixelSize(resources,
+ R.dimen.desktop_mode_handle_menu_corner_radius);
+ mMoreActionsPillHeight = loadDimensionPixelSize(resources,
+ R.dimen.desktop_mode_handle_menu_more_actions_pill_height);
}
@Override
@@ -155,6 +188,22 @@
taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM;
final boolean isDragResizeable = isFreeform && taskInfo.isResizeable;
+ if (mHandleMenuAppInfoPill != null) {
+ updateHandleMenuPillPositions();
+ startT.setPosition(mHandleMenuAppInfoPill.mWindowSurface,
+ mHandleMenuAppInfoPillPosition.x, mHandleMenuAppInfoPillPosition.y);
+
+ // Only show windowing buttons in proto2. Proto1 uses a system-level mode only.
+ final boolean shouldShowWindowingPill = DesktopModeStatus.isProto2Enabled();
+ if (shouldShowWindowingPill) {
+ startT.setPosition(mHandleMenuWindowingPill.mWindowSurface,
+ mHandleMenuWindowingPillPosition.x, mHandleMenuWindowingPillPosition.y);
+ }
+
+ startT.setPosition(mHandleMenuMoreActionsPill.mWindowSurface,
+ mHandleMenuMoreActionsPillPosition.x, mHandleMenuMoreActionsPillPosition.y);
+ }
+
final WindowDecorLinearLayout oldRootView = mResult.mRootView;
final SurfaceControl oldDecorationSurface = mDecorationContainerSurface;
final WindowContainerTransaction wct = new WindowContainerTransaction();
@@ -271,64 +320,17 @@
*/
void createHandleMenu() {
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
- final Resources resources = mDecorWindowContext.getResources();
- final int captionWidth = mTaskInfo.getConfiguration()
- .windowConfiguration.getBounds().width();
- final int menuWidth = loadDimensionPixelSize(resources,
- R.dimen.desktop_mode_handle_menu_width);
- final int shadowRadius = loadDimensionPixelSize(resources,
- R.dimen.desktop_mode_handle_menu_shadow_radius);
- final int cornerRadius = loadDimensionPixelSize(resources,
- R.dimen.desktop_mode_handle_menu_corner_radius);
- final int marginMenuTop = loadDimensionPixelSize(resources,
- R.dimen.desktop_mode_handle_menu_margin_top);
- final int marginMenuStart = loadDimensionPixelSize(resources,
- R.dimen.desktop_mode_handle_menu_margin_start);
- final int marginMenuSpacing = loadDimensionPixelSize(resources,
- R.dimen.desktop_mode_handle_menu_pill_spacing_margin);
- final int appInfoPillHeight = loadDimensionPixelSize(resources,
- R.dimen.desktop_mode_handle_menu_app_info_pill_height);
- final int windowingPillHeight = loadDimensionPixelSize(resources,
- R.dimen.desktop_mode_handle_menu_windowing_pill_height);
- final int moreActionsPillHeight = loadDimensionPixelSize(resources,
- R.dimen.desktop_mode_handle_menu_more_actions_pill_height);
+ updateHandleMenuPillPositions();
- final int menuX, menuY;
- if (mRelayoutParams.mLayoutResId
- == R.layout.desktop_mode_app_controls_window_decor) {
- // Align the handle menu to the left of the caption.
- menuX = mRelayoutParams.mCaptionX - mResult.mDecorContainerOffsetX + marginMenuStart;
- menuY = mRelayoutParams.mCaptionY - mResult.mDecorContainerOffsetY + marginMenuTop;
- } else {
- // Position the handle menu at the center of the caption.
- menuX = mRelayoutParams.mCaptionX + (captionWidth / 2) - (menuWidth / 2)
- - mResult.mDecorContainerOffsetX;
- menuY = mRelayoutParams.mCaptionY - mResult.mDecorContainerOffsetY + marginMenuStart;
- }
-
- final int appInfoPillY = menuY;
- createAppInfoPill(t, menuX, appInfoPillY, menuWidth, appInfoPillHeight, shadowRadius,
- cornerRadius);
+ createAppInfoPill(t);
// Only show windowing buttons in proto2. Proto1 uses a system-level mode only.
final boolean shouldShowWindowingPill = DesktopModeStatus.isProto2Enabled();
- final int windowingPillY = appInfoPillY + appInfoPillHeight + marginMenuSpacing;
if (shouldShowWindowingPill) {
- createWindowingPill(t, menuX, windowingPillY, menuWidth, windowingPillHeight,
- shadowRadius,
- cornerRadius);
+ createWindowingPill(t);
}
- final int moreActionsPillY;
- if (shouldShowWindowingPill) {
- // Take into account the windowing pill height and margins.
- moreActionsPillY = windowingPillY + windowingPillHeight + marginMenuSpacing;
- } else {
- // Just start after the end of the app info pill + margins.
- moreActionsPillY = appInfoPillY + appInfoPillHeight + marginMenuSpacing;
- }
- createMoreActionsPill(t, menuX, moreActionsPillY, menuWidth, moreActionsPillHeight,
- shadowRadius, cornerRadius);
+ createMoreActionsPill(t);
mSyncQueue.runInSync(transaction -> {
transaction.merge(t);
@@ -337,31 +339,31 @@
setupHandleMenu(shouldShowWindowingPill);
}
- private void createAppInfoPill(SurfaceControl.Transaction t, int x, int y, int width,
- int height, int shadowRadius, int cornerRadius) {
- mHandleMenuAppInfoPillPosition.set(x, y);
+ private void createAppInfoPill(SurfaceControl.Transaction t) {
+ final int x = (int) mHandleMenuAppInfoPillPosition.x;
+ final int y = (int) mHandleMenuAppInfoPillPosition.y;
mHandleMenuAppInfoPill = addWindow(
R.layout.desktop_mode_window_decor_handle_menu_app_info_pill,
"Menu's app info pill",
- t, x, y, width, height, shadowRadius, cornerRadius);
+ t, x, y, mMenuWidth, mAppInfoPillHeight, mShadowRadius, mCornerRadius);
}
- private void createWindowingPill(SurfaceControl.Transaction t, int x, int y, int width,
- int height, int shadowRadius, int cornerRadius) {
- mHandleMenuWindowingPillPosition.set(x, y);
+ private void createWindowingPill(SurfaceControl.Transaction t) {
+ final int x = (int) mHandleMenuWindowingPillPosition.x;
+ final int y = (int) mHandleMenuWindowingPillPosition.y;
mHandleMenuWindowingPill = addWindow(
R.layout.desktop_mode_window_decor_handle_menu_windowing_pill,
"Menu's windowing pill",
- t, x, y, width, height, shadowRadius, cornerRadius);
+ t, x, y, mMenuWidth, mWindowingPillHeight, mShadowRadius, mCornerRadius);
}
- private void createMoreActionsPill(SurfaceControl.Transaction t, int x, int y, int width,
- int height, int shadowRadius, int cornerRadius) {
- mHandleMenuMoreActionsPillPosition.set(x, y);
+ private void createMoreActionsPill(SurfaceControl.Transaction t) {
+ final int x = (int) mHandleMenuMoreActionsPillPosition.x;
+ final int y = (int) mHandleMenuMoreActionsPillPosition.y;
mHandleMenuMoreActionsPill = addWindow(
R.layout.desktop_mode_window_decor_handle_menu_more_actions_pill,
"Menu's more actions pill",
- t, x, y, width, height, shadowRadius, cornerRadius);
+ t, x, y, mMenuWidth, mMoreActionsPillHeight, mShadowRadius, mCornerRadius);
}
private void setupHandleMenu(boolean windowingPillShown) {
@@ -413,6 +415,45 @@
}
/**
+ * Updates the handle menu pills' position variables to reflect their next positions
+ */
+ private void updateHandleMenuPillPositions() {
+ final int menuX, menuY;
+ final int captionWidth = mTaskInfo.getConfiguration()
+ .windowConfiguration.getBounds().width();
+ if (mRelayoutParams.mLayoutResId
+ == R.layout.desktop_mode_app_controls_window_decor) {
+ // Align the handle menu to the left of the caption.
+ menuX = mRelayoutParams.mCaptionX - mResult.mDecorContainerOffsetX + mMarginMenuStart;
+ menuY = mRelayoutParams.mCaptionY - mResult.mDecorContainerOffsetY + mMarginMenuTop;
+ } else {
+ // Position the handle menu at the center of the caption.
+ menuX = mRelayoutParams.mCaptionX + (captionWidth / 2) - (mMenuWidth / 2)
+ - mResult.mDecorContainerOffsetX;
+ menuY = mRelayoutParams.mCaptionY - mResult.mDecorContainerOffsetY + mMarginMenuStart;
+ }
+
+ // App Info pill setup.
+ final int appInfoPillY = menuY;
+ mHandleMenuAppInfoPillPosition.set(menuX, appInfoPillY);
+
+ // Only show windowing buttons in proto2. Proto1 uses a system-level mode only.
+ final boolean shouldShowWindowingPill = DesktopModeStatus.isProto2Enabled();
+
+ final int windowingPillY, moreActionsPillY;
+ if (shouldShowWindowingPill) {
+ windowingPillY = appInfoPillY + mAppInfoPillHeight + mMarginMenuSpacing;
+ mHandleMenuWindowingPillPosition.set(menuX, windowingPillY);
+ moreActionsPillY = windowingPillY + mWindowingPillHeight + mMarginMenuSpacing;
+ mHandleMenuMoreActionsPillPosition.set(menuX, moreActionsPillY);
+ } else {
+ // Just start after the end of the app info pill + margins.
+ moreActionsPillY = appInfoPillY + mAppInfoPillHeight + mMarginMenuSpacing;
+ mHandleMenuMoreActionsPillPosition.set(menuX, moreActionsPillY);
+ }
+ }
+
+ /**
* Close the handle menu window
*/
void closeHandleMenu() {
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 5d79104..70c36a5 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -55,6 +55,10 @@
// GCC false-positives on this warning, and since we -Werror that's
// a problem
"-Wno-free-nonheap-object",
+
+ // Do not de-optimise cold code paths in AFDO.
+ // Some code paths might be infrequently executed but critical to latency.
+ "-fno-profile-sample-accurate",
],
include_dirs: [
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 8ea71f1..1f92968 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -28,6 +28,7 @@
#include <SkMultiPictureDocument.h>
#include <SkOverdrawCanvas.h>
#include <SkOverdrawColorFilter.h>
+#include <SkPaintFilterCanvas.h>
#include <SkPicture.h>
#include <SkPictureRecorder.h>
#include <SkRect.h>
@@ -36,15 +37,15 @@
#include <SkStream.h>
#include <SkString.h>
#include <SkTypeface.h>
-#include "include/gpu/GpuTypes.h" // from Skia
#include <android-base/properties.h>
+#include <gui/TraceUtils.h>
#include <unistd.h>
#include <sstream>
-#include <gui/TraceUtils.h>
#include "LightingInfo.h"
#include "VectorDrawable.h"
+#include "include/gpu/GpuTypes.h" // from Skia
#include "thread/CommonPool.h"
#include "tools/SkSharingProc.h"
#include "utils/Color.h"
@@ -449,6 +450,23 @@
}
}
+class ForceDitherCanvas : public SkPaintFilterCanvas {
+public:
+ ForceDitherCanvas(SkCanvas* canvas) : SkPaintFilterCanvas(canvas) {}
+
+protected:
+ bool onFilter(SkPaint& paint) const override {
+ paint.setDither(true);
+ return true;
+ }
+
+ void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override {
+ // We unroll the drawable using "this" canvas, so that draw calls contained inside will
+ // get dithering applied
+ drawable->draw(this, matrix);
+ }
+};
+
void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& clip,
const std::vector<sp<RenderNode>>& nodes, bool opaque,
const Rect& contentDrawBounds, sk_sp<SkSurface> surface,
@@ -503,6 +521,12 @@
canvas->clear(SK_ColorTRANSPARENT);
}
+ std::optional<ForceDitherCanvas> forceDitherCanvas;
+ if (shouldForceDither()) {
+ forceDitherCanvas.emplace(canvas);
+ canvas = &forceDitherCanvas.value();
+ }
+
if (1 == nodes.size()) {
if (!nodes[0]->nothingToDraw()) {
RenderNodeDrawable root(nodes[0].get(), canvas);
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index befee89..0763b06 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -98,6 +98,8 @@
bool isCapturingSkp() const { return mCaptureMode != CaptureMode::None; }
+ virtual bool shouldForceDither() const { return mColorMode != ColorMode::Default; }
+
private:
void renderFrameImpl(const SkRect& clip,
const std::vector<sp<RenderNode>>& nodes, bool opaque,
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index c8f2e69..6f1b99b 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -203,6 +203,11 @@
return nullptr;
}
+bool SkiaVulkanPipeline::shouldForceDither() const {
+ if (mVkSurface && mVkSurface->isBeyond8Bit()) return false;
+ return SkiaPipeline::shouldForceDither();
+}
+
void SkiaVulkanPipeline::onContextDestroyed() {
if (mVkSurface) {
vulkanManager().destroySurface(mVkSurface);
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index d921ddb..0713e93 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -63,6 +63,8 @@
protected:
void onContextDestroyed() override;
+ bool shouldForceDither() const override;
+
private:
renderthread::VulkanManager& vulkanManager();
renderthread::VulkanSurface* mVkSurface = nullptr;
diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp
index 21b6c44..ae4f057 100644
--- a/libs/hwui/renderthread/VulkanSurface.cpp
+++ b/libs/hwui/renderthread/VulkanSurface.cpp
@@ -530,6 +530,16 @@
}
}
+bool VulkanSurface::isBeyond8Bit() const {
+ switch (mWindowInfo.bufferFormat) {
+ case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
+ case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
+ return true;
+ default:
+ return false;
+ }
+}
+
} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/renderthread/VulkanSurface.h b/libs/hwui/renderthread/VulkanSurface.h
index e2ddc6b..3b69b73 100644
--- a/libs/hwui/renderthread/VulkanSurface.h
+++ b/libs/hwui/renderthread/VulkanSurface.h
@@ -48,6 +48,8 @@
void setColorSpace(sk_sp<SkColorSpace> colorSpace);
+ bool isBeyond8Bit() const;
+
private:
/*
* All structs/methods in this private section are specifically for use by the VulkanManager
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index b4fbc97..b1d2e33 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -661,7 +661,10 @@
*/
public static final int ENCODED_SURROUND_OUTPUT_MANUAL = 3;
- /** @hide */
+ /**
+ * @hide
+ * This list contains all the flags that can be used in internal APIs for volume
+ * related operations */
@IntDef(flag = true, prefix = "FLAG", value = {
FLAG_SHOW_UI,
FLAG_ALLOW_RINGER_MODES,
@@ -681,16 +684,64 @@
@Retention(RetentionPolicy.SOURCE)
public @interface Flags {}
- /** @hide */
+ /**
+ * @hide
+ * This list contains all the flags that can be used in SDK-visible methods for volume
+ * related operations.
+ * See for instance {@link #adjustVolume(int, int)},
+ * {@link #adjustStreamVolume(int, int, int)},
+ * {@link #adjustSuggestedStreamVolume(int, int, int)},
+ * {@link #adjustVolumeGroupVolume(int, int, int)},
+ * {@link #setStreamVolume(int, int, int)}
+ * The list contains all volume flags, but the values commented out of the list are there for
+ * maintenance reasons (for when adding flags or changing their visibility),
+ * and to document why some are not in the list (hidden or SystemApi). */
@IntDef(flag = true, prefix = "FLAG", value = {
FLAG_SHOW_UI,
FLAG_ALLOW_RINGER_MODES,
FLAG_PLAY_SOUND,
FLAG_REMOVE_SOUND_AND_VIBRATE,
FLAG_VIBRATE,
+ //FLAG_FIXED_VOLUME, removed due to @hide
+ //FLAG_BLUETOOTH_ABS_VOLUME, removed due to @SystemApi
+ //FLAG_SHOW_SILENT_HINT, removed due to @hide
+ //FLAG_HDMI_SYSTEM_AUDIO_VOLUME, removed due to @hide
+ //FLAG_ACTIVE_MEDIA_ONLY, removed due to @hide
+ //FLAG_SHOW_UI_WARNINGS, removed due to @hide
+ //FLAG_SHOW_VIBRATE_HINT, removed due to @hide
+ //FLAG_FROM_KEY, removed due to @SystemApi
+ //FLAG_ABSOLUTE_VOLUME, removed due to @hide
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PublicVolumeFlags {}
+
+ /**
+ * @hide
+ * Like PublicVolumeFlags, but for all the flags that can be used in @SystemApi methods for
+ * volume related operations.
+ * See for instance {@link #setVolumeIndexForAttributes(AudioAttributes, int, int)},
+ * {@link #setVolumeGroupVolumeIndex(int, int, int)},
+ * {@link #setStreamVolumeForUid(int, int, int, String, int, int, int)},
+ * {@link #adjustStreamVolumeForUid(int, int, int, String, int, int, int)},
+ * {@link #adjustSuggestedStreamVolumeForUid(int, int, int, String, int, int, int)}
+ * The list contains all volume flags, but the values commented out of the list are there for
+ * maintenance reasons (for when adding flags or changing their visibility),
+ * and to document which hidden values are not in the list. */
+ @IntDef(flag = true, prefix = "FLAG", value = {
+ FLAG_SHOW_UI,
+ FLAG_ALLOW_RINGER_MODES,
+ FLAG_PLAY_SOUND,
+ FLAG_REMOVE_SOUND_AND_VIBRATE,
+ FLAG_VIBRATE,
+ //FLAG_FIXED_VOLUME, removed due to @hide
FLAG_BLUETOOTH_ABS_VOLUME,
- FLAG_HDMI_SYSTEM_AUDIO_VOLUME,
+ //FLAG_SHOW_SILENT_HINT, removed due to @hide
+ //FLAG_HDMI_SYSTEM_AUDIO_VOLUME, removed due to @hide
+ //FLAG_ACTIVE_MEDIA_ONLY, removed due to @hide
+ //FLAG_SHOW_UI_WARNINGS, removed due to @hide
+ //FLAG_SHOW_VIBRATE_HINT, removed due to @hide
FLAG_FROM_KEY,
+ //FLAG_ABSOLUTE_VOLUME, removed due to @hide
})
@Retention(RetentionPolicy.SOURCE)
public @interface SystemVolumeFlags {}
@@ -981,13 +1032,13 @@
* @param direction The direction to adjust the volume. One of
* {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
* {@link #ADJUST_SAME}.
- * @param flags One or more flags.
+ * @param flags
* @see #adjustVolume(int, int)
* @see #setStreamVolume(int, int, int)
* @throws SecurityException if the adjustment triggers a Do Not Disturb change
* and the caller is not granted notification policy access.
*/
- public void adjustStreamVolume(int streamType, int direction, int flags) {
+ public void adjustStreamVolume(int streamType, int direction, @PublicVolumeFlags int flags) {
final IAudioService service = getService();
try {
service.adjustStreamVolumeWithAttribution(streamType, direction, flags,
@@ -1014,13 +1065,13 @@
* {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
* {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
* {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
- * @param flags One or more flags.
+ * @param flags
* @see #adjustSuggestedStreamVolume(int, int, int)
* @see #adjustStreamVolume(int, int, int)
* @see #setStreamVolume(int, int, int)
* @see #isVolumeFixed()
*/
- public void adjustVolume(int direction, int flags) {
+ public void adjustVolume(int direction, @PublicVolumeFlags int flags) {
MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags);
}
@@ -1043,13 +1094,14 @@
* @param suggestedStreamType The stream type that will be used if there
* isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is
* valid here.
- * @param flags One or more flags.
+ * @param flags
* @see #adjustVolume(int, int)
* @see #adjustStreamVolume(int, int, int)
* @see #setStreamVolume(int, int, int)
* @see #isVolumeFixed()
*/
- public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
+ public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType,
+ @PublicVolumeFlags int flags) {
MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags);
}
@@ -1334,14 +1386,14 @@
* @param streamType The stream whose volume index should be set.
* @param index The volume index to set. See
* {@link #getStreamMaxVolume(int)} for the largest valid value.
- * @param flags One or more flags.
+ * @param flags
* @see #getStreamMaxVolume(int)
* @see #getStreamVolume(int)
* @see #isVolumeFixed()
* @throws SecurityException if the volume change triggers a Do Not Disturb change
* and the caller is not granted notification policy access.
*/
- public void setStreamVolume(int streamType, int index, int flags) {
+ public void setStreamVolume(int streamType, int index, @PublicVolumeFlags int flags) {
final IAudioService service = getService();
try {
service.setStreamVolumeWithAttribution(streamType, index, flags,
@@ -1357,7 +1409,7 @@
* @param index The volume index to set. See
* {@link #getMaxVolumeIndexForAttributes(AudioAttributes)} for the largest valid value
* {@link #getMinVolumeIndexForAttributes(AudioAttributes)} for the lowest valid value.
- * @param flags One or more flags.
+ * @param flags
* @see #getMaxVolumeIndexForAttributes(AudioAttributes)
* @see #getMinVolumeIndexForAttributes(AudioAttributes)
* @see #isVolumeFixed()
@@ -1365,7 +1417,8 @@
*/
@SystemApi
@RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
- public void setVolumeIndexForAttributes(@NonNull AudioAttributes attr, int index, int flags) {
+ public void setVolumeIndexForAttributes(@NonNull AudioAttributes attr, int index,
+ @SystemVolumeFlags int flags) {
Preconditions.checkNotNull(attr, "attr must not be null");
final IAudioService service = getService();
int groupId = getVolumeGroupIdForAttributes(attr);
@@ -1451,7 +1504,7 @@
* @param index The volume index to set. See
* {@link #getVolumeGroupMaxVolumeIndex(id)} for the largest valid value
* {@link #getVolumeGroupMinVolumeIndex(id)} for the lowest valid value.
- * @param flags One or more flags.
+ * @param flags
* @hide
*/
@SystemApi
@@ -1552,11 +1605,11 @@
* @param direction The direction to adjust the volume. One of
* {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
* {@link #ADJUST_SAME}.
- * @param flags One or more flags.
+ * @param flags
* @throws SecurityException if the adjustment triggers a Do Not Disturb change and the caller
* is not granted notification policy access.
*/
- public void adjustVolumeGroupVolume(int groupId, int direction, @SystemVolumeFlags int flags) {
+ public void adjustVolumeGroupVolume(int groupId, int direction, @PublicVolumeFlags int flags) {
IAudioService service = getService();
try {
service.adjustVolumeGroupVolume(groupId, direction, flags,
@@ -8234,7 +8287,7 @@
* {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
* {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
* {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
- * @param flags One or more flags.
+ * @param flags
* @param packageName the package name of client application
* @param uid the uid of client application
* @param pid the pid of client application
@@ -8247,7 +8300,8 @@
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public void adjustSuggestedStreamVolumeForUid(int suggestedStreamType, int direction, int flags,
+ public void adjustSuggestedStreamVolumeForUid(int suggestedStreamType, int direction,
+ @SystemVolumeFlags int flags,
@NonNull String packageName, int uid, int pid, int targetSdkVersion) {
try {
getService().adjustSuggestedStreamVolumeForUid(suggestedStreamType, direction, flags,
@@ -8277,7 +8331,7 @@
* @param direction The direction to adjust the volume. One of
* {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
* {@link #ADJUST_SAME}.
- * @param flags One or more flags.
+ * @param flags
* @param packageName the package name of client application
* @param uid the uid of client application
* @param pid the pid of client application
@@ -8290,7 +8344,8 @@
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
+ public void adjustStreamVolumeForUid(int streamType, int direction,
+ @SystemVolumeFlags int flags,
@NonNull String packageName, int uid, int pid, int targetSdkVersion) {
try {
getService().adjustStreamVolumeForUid(streamType, direction, flags, packageName, uid,
@@ -8314,7 +8369,7 @@
* @param streamType The stream whose volume index should be set.
* @param index The volume index to set. See
* {@link #getStreamMaxVolume(int)} for the largest valid value.
- * @param flags One or more flags.
+ * @param flags
* @param packageName the package name of client application
* @param uid the uid of client application
* @param pid the pid of client application
@@ -8328,7 +8383,8 @@
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public void setStreamVolumeForUid(int streamType, int index, int flags,
+ public void setStreamVolumeForUid(int streamType, int index,
+ @SystemVolumeFlags int flags,
@NonNull String packageName, int uid, int pid, int targetSdkVersion) {
try {
getService().setStreamVolumeForUid(streamType, index, flags, packageName, uid, pid,
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index f9d4efe..fe5afc5 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -268,7 +268,7 @@
boolean isVolumeControlUsingVolumeGroups();
@EnforcePermission("MODIFY_AUDIO_SETTINGS_PRIVILEGED")
- oneway void registerStreamAliasingDispatcher(IStreamAliasingDispatcher isad, boolean register);
+ void registerStreamAliasingDispatcher(IStreamAliasingDispatcher isad, boolean register);
@EnforcePermission("MODIFY_AUDIO_SETTINGS_PRIVILEGED")
void setNotifAliasRingForTest(boolean alias);
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 031c3ff..0d9bd65 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -1169,7 +1169,7 @@
* @param flags flags containing extra action or information regarding the volume change
*/
void onVolumeChanged(@NonNull MediaSession.Token sessionToken,
- @AudioManager.Flags int flags);
+ @AudioManager.SystemVolumeFlags int flags);
/**
* Called when the default remote session is changed where the default remote session
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 9a4aa33..dea7f03 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -43,6 +43,8 @@
#include <android_runtime/android_hardware_HardwareBuffer.h>
+#include <android-base/stringprintf.h>
+
#include <binder/MemoryDealer.h>
#include <cutils/compiler.h>
@@ -1276,7 +1278,8 @@
ALOGE("Could not create MediaCodec.BufferInfo.");
env->ExceptionClear();
}
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Fatal error: could not create MediaCodec.BufferInfo object");
return;
}
@@ -1309,7 +1312,8 @@
ALOGE("Could not create CodecException object.");
env->ExceptionClear();
}
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Fatal error: could not create CodecException object");
return;
}
@@ -1322,7 +1326,9 @@
CHECK(msg->findMessage("format", &format));
if (OK != ConvertMessageToMap(env, format, &obj)) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Fatal error: failed to convert format "
+ "from native to Java object");
return;
}
@@ -1353,7 +1359,8 @@
status_t err = ConvertMessageToMap(env, data, &obj);
if (err != OK) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Fatal error: failed to convert format from native to Java object");
return;
}
@@ -1374,7 +1381,8 @@
status_t err = ConvertMessageToMap(env, data, &obj);
if (err != OK) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Fatal error: failed to convert format from native to Java object");
return;
}
@@ -1385,6 +1393,18 @@
env->DeleteLocalRef(obj);
}
+std::string JMediaCodec::getExceptionMessage(const char *msg = nullptr) const {
+ if (mCodec == nullptr) {
+ return msg ?: "";
+ }
+ std::string prefix = "";
+ if (msg && msg[0] != '\0') {
+ prefix.append(msg);
+ prefix.append("\n");
+ }
+ return prefix + mCodec->getErrorLog().extract();
+}
+
void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case kWhatCallbackNotify:
@@ -1471,9 +1491,17 @@
env->Throw(exception);
}
+static std::string GetExceptionMessage(const sp<JMediaCodec> &codec, const char *msg) {
+ if (codec == NULL) {
+ return msg ?: "codec is released already";
+ }
+ return codec->getExceptionMessage(msg);
+}
+
static jint throwExceptionAsNecessary(
JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL,
- const char *msg = NULL, const sp<ICrypto>& crypto = NULL) {
+ const char *msg = NULL, const sp<ICrypto>& crypto = NULL,
+ const sp<JMediaCodec> &codec = NULL) {
switch (err) {
case OK:
return 0;
@@ -1488,23 +1516,38 @@
return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
case INVALID_OPERATION:
- jniThrowException(env, "java/lang/IllegalStateException", msg);
+ jniThrowException(
+ env, "java/lang/IllegalStateException",
+ GetExceptionMessage(codec, msg).c_str());
return 0;
case BAD_VALUE:
- jniThrowException(env, "java/lang/IllegalArgumentException", msg);
+ jniThrowException(
+ env, "java/lang/IllegalArgumentException",
+ GetExceptionMessage(codec, msg).c_str());
return 0;
default:
if (isCryptoError(err)) {
- throwCryptoException(env, err, msg, crypto);
+ throwCryptoException(
+ env, err,
+ GetExceptionMessage(codec, msg).c_str(),
+ crypto);
return 0;
}
- throwCodecException(env, err, actionCode, msg);
+ throwCodecException(
+ env, err, actionCode,
+ GetExceptionMessage(codec, msg).c_str());
return 0;
}
}
+static jint throwExceptionAsNecessary(
+ JNIEnv *env, status_t err, const sp<JMediaCodec> &codec,
+ int32_t actionCode = ACTION_CODE_FATAL) {
+ return throwExceptionAsNecessary(env, err, actionCode, NULL, NULL, codec);
+}
+
static void android_media_MediaCodec_native_enableOnFirstTunnelFrameReadyListener(
JNIEnv *env,
jobject thiz,
@@ -1512,13 +1555,13 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
status_t err = codec->enableOnFirstTunnelFrameReadyListener(enabled);
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
static void android_media_MediaCodec_native_enableOnFrameRenderedListener(
@@ -1528,13 +1571,13 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
status_t err = codec->enableOnFrameRenderedListener(enabled);
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
static void android_media_MediaCodec_native_setCallback(
@@ -1544,13 +1587,13 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
status_t err = codec->setCallback(cb);
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
static void android_media_MediaCodec_native_configure(
@@ -1564,7 +1607,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
@@ -1602,7 +1645,7 @@
err = codec->configure(format, bufferProducer, crypto, descrambler, flags);
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
static void android_media_MediaCodec_native_setSurface(
@@ -1612,7 +1655,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
@@ -1631,7 +1674,7 @@
}
status_t err = codec->setSurface(bufferProducer);
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
sp<PersistentSurface> android_media_MediaCodec_getPersistentInputSurface(
@@ -1735,7 +1778,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
@@ -1749,7 +1792,7 @@
}
status_t err = codec->setInputSurface(persistentSurface);
if (err != NO_ERROR) {
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
}
@@ -1759,7 +1802,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return NULL;
}
@@ -1767,7 +1810,7 @@
sp<IGraphicBufferProducer> bufferProducer;
status_t err = codec->createInputSurface(&bufferProducer);
if (err != NO_ERROR) {
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
return NULL;
}
@@ -1782,13 +1825,13 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
status_t err = codec->start();
- throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, "start failed");
+ throwExceptionAsNecessary(env, err, codec);
}
static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
@@ -1797,13 +1840,13 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
status_t err = codec->stop();
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
@@ -1812,7 +1855,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
@@ -1825,7 +1868,7 @@
// trigger an IllegalStateException.
err = UNKNOWN_ERROR;
}
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
@@ -1834,13 +1877,13 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
status_t err = codec->flush();
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
static void android_media_MediaCodec_queueInputBuffer(
@@ -1856,7 +1899,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
@@ -1866,7 +1909,8 @@
index, offset, size, timestampUs, flags, &errorDetailMsg);
throwExceptionAsNecessary(
- env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
+ env, err, ACTION_CODE_FATAL,
+ codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
}
struct NativeCryptoInfo {
@@ -1890,7 +1934,9 @@
} else if (jmode == gCryptoModes.AesCbc) {
mMode = CryptoPlugin::kMode_AES_CBC;
} else {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(
+ env, INVALID_OPERATION, ACTION_CODE_FATAL,
+ base::StringPrintf("unrecognized crypto mode: %d", jmode).c_str());
return;
}
@@ -2026,7 +2072,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
@@ -2056,7 +2102,9 @@
} else if (jmode == gCryptoModes.AesCbc) {
mode = CryptoPlugin::kMode_AES_CBC;
} else {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(
+ env, INVALID_OPERATION, ACTION_CODE_FATAL,
+ base::StringPrintf("Unrecognized crypto mode: %d", jmode).c_str());
return;
}
@@ -2175,8 +2223,8 @@
subSamples = NULL;
throwExceptionAsNecessary(
- env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str(),
- codec->getCrypto());
+ env, err, ACTION_CODE_FATAL,
+ codec->getExceptionMessage(errorDetailMsg.c_str()).c_str(), codec->getCrypto());
}
static jobject android_media_MediaCodec_mapHardwareBuffer(JNIEnv *env, jclass, jobject bufferObj) {
@@ -2518,14 +2566,16 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == nullptr || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
sp<AMessage> tunings;
status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
if (err != OK) {
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(
+ env, err, ACTION_CODE_FATAL,
+ "error occurred while converting tunings from Java to native");
return;
}
@@ -2545,15 +2595,23 @@
}
env->MonitorExit(lock.get());
} else {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(
+ env, INVALID_OPERATION, ACTION_CODE_FATAL,
+ "Failed to grab lock for a LinearBlock object");
return;
}
AString errorDetailMsg;
if (codec->hasCryptoOrDescrambler()) {
if (!memory) {
+ // It means there was an unexpected failure in extractMemoryFromContext above
ALOGI("queueLinearBlock: no ashmem memory for encrypted content");
- throwExceptionAsNecessary(env, BAD_VALUE);
+ throwExceptionAsNecessary(
+ env, BAD_VALUE, ACTION_CODE_FATAL,
+ "Unexpected error: the input buffer is not compatible with "
+ "the secure codec, and a fallback logic failed.\n"
+ "Suggestion: please try including the secure codec when calling "
+ "MediaCodec.LinearBlock#obtain method to obtain a compatible buffer.");
return;
}
auto cryptoInfo =
@@ -2577,14 +2635,22 @@
ALOGI_IF(err != OK, "queueEncryptedLinearBlock returned err = %d", err);
} else {
if (!buffer) {
+ // It means there was an unexpected failure in extractBufferFromContext above
ALOGI("queueLinearBlock: no C2Buffer found");
- throwExceptionAsNecessary(env, BAD_VALUE);
+ throwExceptionAsNecessary(
+ env, BAD_VALUE, ACTION_CODE_FATAL,
+ "Unexpected error: the input buffer is not compatible with "
+ "the non-secure codec, and a fallback logic failed.\n"
+ "Suggestion: please do not include the secure codec when calling "
+ "MediaCodec.LinearBlock#obtain method to obtain a compatible buffer.");
return;
}
err = codec->queueBuffer(
index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
}
- throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, errorDetailMsg.c_str());
+ throwExceptionAsNecessary(
+ env, err, ACTION_CODE_FATAL,
+ codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
}
static void android_media_MediaCodec_native_queueHardwareBuffer(
@@ -2595,14 +2661,16 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
sp<AMessage> tunings;
status_t err = ConvertKeyValueListsToAMessage(env, keys, values, &tunings);
if (err != OK) {
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(
+ env, err, ACTION_CODE_FATAL,
+ "error occurred while converting tunings from Java to native");
return;
}
@@ -2627,7 +2695,9 @@
ALOGW("Failed to wrap AHardwareBuffer into C2GraphicAllocation");
native_handle_close(handle);
native_handle_delete(handle);
- throwExceptionAsNecessary(env, BAD_VALUE);
+ throwExceptionAsNecessary(
+ env, BAD_VALUE, ACTION_CODE_FATAL,
+ "HardwareBuffer not recognized");
return;
}
std::shared_ptr<C2GraphicBlock> block = _C2BlockFactory::CreateGraphicBlock(alloc);
@@ -2636,7 +2706,9 @@
AString errorDetailMsg;
err = codec->queueBuffer(
index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
- throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, errorDetailMsg.c_str());
+ throwExceptionAsNecessary(
+ env, err, ACTION_CODE_FATAL,
+ codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
}
static void android_media_MediaCodec_native_getOutputFrame(
@@ -2646,13 +2718,13 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
status_t err = codec->getOutputFrame(env, frame, index);
if (err != OK) {
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
}
@@ -2663,7 +2735,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return -1;
}
@@ -2674,7 +2746,7 @@
return (jint) index;
}
- return throwExceptionAsNecessary(env, err);
+ return throwExceptionAsNecessary(env, err, codec);
}
static jint android_media_MediaCodec_dequeueOutputBuffer(
@@ -2684,7 +2756,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return 0;
}
@@ -2696,7 +2768,7 @@
return (jint) index;
}
- return throwExceptionAsNecessary(env, err);
+ return throwExceptionAsNecessary(env, err, codec);
}
static void android_media_MediaCodec_releaseOutputBuffer(
@@ -2707,13 +2779,13 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env,
@@ -2722,13 +2794,13 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
status_t err = codec->signalEndOfInputStream();
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
static jobject android_media_MediaCodec_getFormatNative(
@@ -2738,7 +2810,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return NULL;
}
@@ -2749,7 +2821,7 @@
return format;
}
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
return NULL;
}
@@ -2761,7 +2833,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return NULL;
}
@@ -2772,7 +2844,7 @@
return format;
}
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
return NULL;
}
@@ -2784,7 +2856,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return NULL;
}
@@ -2797,7 +2869,7 @@
// if we're out of memory, an exception was already thrown
if (err != NO_MEMORY) {
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
return NULL;
@@ -2810,7 +2882,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return NULL;
}
@@ -2823,7 +2895,7 @@
// if we're out of memory, an exception was already thrown
if (err != NO_MEMORY) {
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
return NULL;
@@ -2836,7 +2908,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return NULL;
}
@@ -2849,7 +2921,7 @@
// if we're out of memory, an exception was already thrown
if (err != NO_MEMORY) {
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
return NULL;
@@ -2862,7 +2934,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return NULL;
}
@@ -2873,7 +2945,7 @@
return name;
}
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
return NULL;
}
@@ -2885,7 +2957,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return NULL;
}
@@ -2896,7 +2968,7 @@
return codecInfoObj;
}
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
return NULL;
}
@@ -2908,7 +2980,8 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ jniThrowException(env, "java/lang/IllegalStateException",
+ GetExceptionMessage(codec, NULL).c_str());
return 0;
}
@@ -2937,7 +3010,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
@@ -2948,7 +3021,7 @@
err = codec->setParameters(params);
}
- throwExceptionAsNecessary(env, err);
+ throwExceptionAsNecessary(env, err, codec);
}
static void android_media_MediaCodec_setVideoScalingMode(
@@ -2956,13 +3029,14 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
if (mode != NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW
&& mode != NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ String8::format("Unrecognized mode: %d", mode));
return;
}
@@ -2974,7 +3048,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
@@ -2986,14 +3060,14 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return NULL;
}
jobject ret = NULL;
status_t status = codec->querySupportedVendorParameters(env, &ret);
if (status != OK) {
- throwExceptionAsNecessary(env, status);
+ throwExceptionAsNecessary(env, status, codec);
}
return ret;
@@ -3004,7 +3078,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return NULL;
}
@@ -3021,13 +3095,13 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
status_t status = codec->subscribeToVendorParameters(env, names);
if (status != OK) {
- throwExceptionAsNecessary(env, status);
+ throwExceptionAsNecessary(env, status, codec);
}
return;
}
@@ -3037,13 +3111,13 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL || codec->initCheck() != OK) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
return;
}
status_t status = codec->unsubscribeFromVendorParameters(env, names);
if (status != OK) {
- throwExceptionAsNecessary(env, status);
+ throwExceptionAsNecessary(env, status, codec);
}
return;
}
@@ -3440,11 +3514,15 @@
if (!context->mReadonlyMapping) {
const C2BufferData data = buffer->data();
if (data.type() != C2BufferData::LINEAR) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(
+ env, INVALID_OPERATION, ACTION_CODE_FATAL,
+ "Underlying buffer is not a linear buffer");
return nullptr;
}
if (data.linearBlocks().size() != 1u) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(
+ env, INVALID_OPERATION, ACTION_CODE_FATAL,
+ "Underlying buffer contains more than one block");
return nullptr;
}
C2ConstLinearBlock block = data.linearBlocks().front();
@@ -3492,7 +3570,9 @@
false, // readOnly
true /* clearBuffer */);
}
- throwExceptionAsNecessary(env, INVALID_OPERATION);
+ throwExceptionAsNecessary(
+ env, INVALID_OPERATION, ACTION_CODE_FATAL,
+ "Underlying buffer is empty");
return nullptr;
}
@@ -3515,7 +3595,9 @@
}
const char *cstr = env->GetStringUTFChars(jstr, nullptr);
if (cstr == nullptr) {
- throwExceptionAsNecessary(env, BAD_VALUE);
+ throwExceptionAsNecessary(
+ env, BAD_VALUE, ACTION_CODE_FATAL,
+ "Error converting Java string to native");
return;
}
names->emplace_back(cstr);
@@ -3567,6 +3649,7 @@
}
status_t err = MediaCodec::CanFetchLinearBlock(names, &isCompatible);
if (err != OK) {
+ // TODO: CodecErrorLog
throwExceptionAsNecessary(env, err);
}
return isCompatible;
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 616c31b..fbaf64f 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -176,6 +176,8 @@
const sp<ICrypto> &getCrypto() { return mCrypto; }
+ std::string getExceptionMessage(const char *msg) const;
+
protected:
virtual ~JMediaCodec();
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
index 6f5015d..24f92c0 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
@@ -5,7 +5,7 @@
* 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
+ * http://www.apache.org/licenses/LICENSE-2.0N
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -74,7 +74,6 @@
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
- Log.d(Constants.LOG_TAG, "Existing activity received new intent")
try {
val viewModel: CredentialSelectorViewModel by viewModels()
val (isCancellationRequest, shouldShowCancellationUi, appDisplayName) =
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 7a97b78..b0a1927 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -3748,7 +3748,7 @@
}
private final class UpgradeController {
- private static final int SETTINGS_VERSION = 216;
+ private static final int SETTINGS_VERSION = 217;
private final int mUserId;
@@ -5711,7 +5711,7 @@
.getSettingLocked(Settings.Secure.CREDENTIAL_SERVICE);
if (currentSetting.isNull()) {
final int resourceId =
- com.android.internal.R.string.config_defaultCredentialProviderService;
+ com.android.internal.R.array.config_defaultCredentialProviderService;
final Resources resources = getContext().getResources();
// If the config has not be defined we might get an exception. We also get
// values from both the string array type and the single string in case the
@@ -5771,6 +5771,39 @@
currentVersion = 216;
}
+ if (currentVersion == 216) {
+ // Version 216: Set a default value for Credential Manager service.
+ // We are doing this migration again because of an incorrect setting.
+
+ final SettingsState secureSettings = getSecureSettingsLocked(userId);
+ final Setting currentSetting = secureSettings
+ .getSettingLocked(Settings.Secure.CREDENTIAL_SERVICE);
+ if (currentSetting.isNull()) {
+ final int resourceId =
+ com.android.internal.R.array.config_defaultCredentialProviderService;
+ final Resources resources = getContext().getResources();
+ // If the config has not be defined we might get an exception.
+ final List<String> providers = new ArrayList<>();
+ try {
+ providers.addAll(Arrays.asList(resources.getStringArray(resourceId)));
+ } catch (Resources.NotFoundException e) {
+ Slog.w(LOG_TAG,
+ "Get default array Cred Provider not found: " + e.toString());
+ }
+
+ if (!providers.isEmpty()) {
+ final String defaultValue = String.join(":", providers);
+ Slog.d(LOG_TAG, "Setting [" + defaultValue + "] as CredMan Service "
+ + "for user " + userId);
+ secureSettings.insertSettingOverrideableByRestoreLocked(
+ Settings.Secure.CREDENTIAL_SERVICE, defaultValue, null, true,
+ SettingsState.SYSTEM_PACKAGE_NAME);
+ }
+ }
+
+ currentVersion = 217;
+ }
+
// vXXX: Add new settings above this point.
if (currentVersion != newVersion) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/WritableNamespacePrefixes.java b/packages/SettingsProvider/src/com/android/providers/settings/WritableNamespacePrefixes.java
index df27f6a..bd99a8b 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/WritableNamespacePrefixes.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/WritableNamespacePrefixes.java
@@ -170,6 +170,7 @@
"widget",
"wifi",
"window_manager",
- "window_manager_native_boot"
+ "window_manager_native_boot",
+ "wrong"
));
}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index ff57052..36a0b5d 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -872,6 +872,20 @@
</intent-filter>
</activity>
+ <activity
+ android:name=".contrast.ContrastDialogActivity"
+ android:label="@string/quick_settings_contrast_label"
+ android:theme="@style/Theme.SystemUI.ContrastDialog"
+ android:finishOnCloseSystemDialogs="true"
+ android:launchMode="singleInstance"
+ android:excludeFromRecents="true"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="com.android.intent.action.SHOW_CONTRAST_DIALOG" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
<activity android:name=".ForegroundServicesDialog"
android:process=":fgservices"
android:excludeFromRecents="true"
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
index 4df7a44..3ec3b5c 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
@@ -25,8 +25,10 @@
import androidx.annotation.VisibleForTesting
import com.android.systemui.customization.R
import com.android.systemui.plugins.ClockAnimations
+import com.android.systemui.plugins.ClockConfig
import com.android.systemui.plugins.ClockController
import com.android.systemui.plugins.ClockEvents
+import com.android.systemui.plugins.ClockFaceConfig
import com.android.systemui.plugins.ClockFaceController
import com.android.systemui.plugins.ClockFaceEvents
import com.android.systemui.plugins.ClockSettings
@@ -63,6 +65,8 @@
override lateinit var animations: DefaultClockAnimations
private set
+ override val config = ClockConfig(hasCustomPositionUpdatedAnimation = true)
+
init {
val parent = FrameLayout(ctx)
smallClock =
@@ -103,6 +107,8 @@
private var isRegionDark = false
protected var targetRegion: Rect? = null
+ override val config = ClockFaceConfig()
+
override var logBuffer: LogBuffer?
get() = view.logBuffer
set(value) {
@@ -254,9 +260,6 @@
override fun onPositionUpdated(fromRect: Rect, toRect: Rect, fraction: Float) {
largeClock.moveForSplitShade(fromRect, toRect, fraction)
}
-
- override val hasCustomPositionUpdatedAnimation: Boolean
- get() = true
}
class AnimationState(
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
index c279053..322fc77 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
@@ -63,6 +63,9 @@
/** A large version of the clock, appropriate when a bigger viewport is available */
val largeClock: ClockFaceController
+ /** Determines the way the hosting app should behave when rendering either clock face */
+ val config: ClockConfig
+
/** Events that clocks may need to respond to */
val events: ClockEvents
@@ -91,6 +94,9 @@
/** View that renders the clock face */
val view: View
+ /** Determines the way the hosting app should behave when rendering this clock face */
+ val config: ClockFaceConfig
+
/** Events specific to this clock face */
val events: ClockFaceEvents
@@ -109,9 +115,6 @@
/** Call whenever the locale changes */
fun onLocaleChanged(locale: Locale) {}
- val isReactiveToTone
- get() = true
-
/** Call whenever the color palette should update */
fun onColorPaletteChanged(resources: Resources) {}
@@ -144,14 +147,6 @@
* 0.0 -> clock is scaled down in the shade; previewRatio is previewSize / screenSize
*/
fun onPickerCarouselSwiping(swipingFraction: Float, previewRatio: Float) {}
-
- /**
- * Whether this clock has a custom position update animation. If true, the keyguard will call
- * `onPositionUpdated` to notify the clock of a position update animation. If false, a default
- * animation will be used (e.g. a simple translation).
- */
- val hasCustomPositionUpdatedAnimation
- get() = false
}
/** Events that have specific data about the related face */
@@ -159,14 +154,6 @@
/** Call every time tick */
fun onTimeTick() {}
- /** Expected interval between calls to onTimeTick. Can always reduce to PER_MINUTE in AOD. */
- val tickRate: ClockTickRate
- get() = ClockTickRate.PER_MINUTE
-
- /** Call to check whether the clock consumes weather data */
- val hasCustomWeatherDataDisplay: Boolean
- get() = false
-
/**
* Region Darkness specific to the clock face.
* - isRegionDark = dark theme -> clock should be light
@@ -203,6 +190,28 @@
val name: String,
)
+/** Render configuration for the full clock. Modifies the way systemUI behaves with this clock. */
+data class ClockConfig(
+ /**
+ * Whether this clock has a custom position update animation. If true, the keyguard will call
+ * `onPositionUpdated` to notify the clock of a position update animation. If false, a default
+ * animation will be used (e.g. a simple translation).
+ */
+ val hasCustomPositionUpdatedAnimation: Boolean = false,
+
+ /** True if the clock will react to tone changes in the seed color. */
+ val isReactiveToTone: Boolean = true,
+)
+
+/** Render configuration options for a clock face. Modifies the way SystemUI behaves. */
+data class ClockFaceConfig(
+ /** Expected interval between calls to onTimeTick. Can always reduce to PER_MINUTE in AOD. */
+ val tickRate: ClockTickRate = ClockTickRate.PER_MINUTE,
+
+ /** Call to check whether the clock consumes weather data */
+ val hasCustomWeatherDataDisplay: Boolean = false,
+)
+
/** Structure for keeping clock-specific settings */
@Keep
data class ClockSettings(
diff --git a/packages/SystemUI/res/drawable/contrast_dialog_button_background.xml b/packages/SystemUI/res/drawable/contrast_dialog_button_background.xml
new file mode 100644
index 0000000..4181220
--- /dev/null
+++ b/packages/SystemUI/res/drawable/contrast_dialog_button_background.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright 2023, The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+-->
+<selector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+
+ <item android:state_selected="true">
+ <shape android:shape="rectangle">
+ <solid android:color="?androidprv:attr/colorSurfaceHighlight" />
+ <stroke
+ android:color="?androidprv:attr/colorAccentPrimary"
+ android:width="@dimen/contrast_dialog_button_stroke_width" />
+ <corners android:radius="@dimen/contrast_dialog_button_radius"/>
+ </shape>
+ </item>
+
+ <item>
+ <layer-list>
+ <item android:top="@dimen/contrast_dialog_button_stroke_width"
+ android:bottom="@dimen/contrast_dialog_button_stroke_width"
+ android:left="@dimen/contrast_dialog_button_stroke_width"
+ android:right="@dimen/contrast_dialog_button_stroke_width">
+ <shape android:shape="rectangle">
+ <solid android:color="?androidprv:attr/colorSurfaceHighlight" />
+ <corners android:radius="@dimen/contrast_dialog_button_radius"/>
+ </shape>
+ </item>
+ </layer-list>
+ </item>
+</selector>
diff --git a/packages/SystemUI/res/drawable/ic_contrast_high.xml b/packages/SystemUI/res/drawable/ic_contrast_high.xml
new file mode 100644
index 0000000..aa5b5ab
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_contrast_high.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector android:autoMirrored="true" android:height="20dp"
+ android:viewportHeight="20" android:viewportWidth="66"
+ android:width="66dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#F2F1E8"
+ android:pathData="M0.5,8C0.5,3.858 3.858,0.5 8,0.5H58C62.142,0.5 65.5,3.858 65.5,8V12C65.5,16.142 62.142,19.5 58,19.5H8C3.858,19.5 0.5,16.142 0.5,12V8Z"
+ android:strokeColor="#1B1C17" android:strokeWidth="1"/>
+ <path android:fillColor="#1B1C17" android:pathData="M11,10m-6,0a6,6 0,1 1,12 0a6,6 0,1 1,-12 0"/>
+ <path android:fillColor="#1B1C17" android:pathData="M23,5L43,5A2,2 0,0 1,45 7L45,7A2,2 0,0 1,43 9L23,9A2,2 0,0 1,21 7L21,7A2,2 0,0 1,23 5z"/>
+ <path android:fillColor="#1B1C17" android:pathData="M23,11L55,11A2,2 0,0 1,57 13L57,13A2,2 0,0 1,55 15L23,15A2,2 0,0 1,21 13L21,13A2,2 0,0 1,23 11z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_contrast_medium.xml b/packages/SystemUI/res/drawable/ic_contrast_medium.xml
new file mode 100644
index 0000000..89519b8
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_contrast_medium.xml
@@ -0,0 +1,23 @@
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector android:autoMirrored="true" android:height="20dp"
+ android:viewportHeight="20" android:viewportWidth="66"
+ android:width="66dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#F2F1E8" android:pathData="M0,8C0,3.582 3.582,0 8,0H58C62.418,0 66,3.582 66,8V12C66,16.418 62.418,20 58,20H8C3.582,20 0,16.418 0,12V8Z"/>
+ <path android:fillColor="#919283" android:pathData="M11,10m-6,0a6,6 0,1 1,12 0a6,6 0,1 1,-12 0"/>
+ <path android:fillColor="#919283" android:pathData="M23,5L43,5A2,2 0,0 1,45 7L45,7A2,2 0,0 1,43 9L23,9A2,2 0,0 1,21 7L21,7A2,2 0,0 1,23 5z"/>
+ <path android:fillColor="#919283" android:pathData="M23,11L55,11A2,2 0,0 1,57 13L57,13A2,2 0,0 1,55 15L23,15A2,2 0,0 1,21 13L21,13A2,2 0,0 1,23 11z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_contrast_standard.xml b/packages/SystemUI/res/drawable/ic_contrast_standard.xml
new file mode 100644
index 0000000..f914975
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_contrast_standard.xml
@@ -0,0 +1,23 @@
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector android:autoMirrored="true" android:height="20dp"
+ android:viewportHeight="20" android:viewportWidth="66"
+ android:width="66dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#C7C8B7" android:pathData="M0,8C0,3.582 3.582,0 8,0H58C62.418,0 66,3.582 66,8V12C66,16.418 62.418,20 58,20H8C3.582,20 0,16.418 0,12V8Z"/>
+ <path android:fillColor="#919283" android:pathData="M11,10m-6,0a6,6 0,1 1,12 0a6,6 0,1 1,-12 0"/>
+ <path android:fillColor="#919283" android:pathData="M23,5L43,5A2,2 0,0 1,45 7L45,7A2,2 0,0 1,43 9L23,9A2,2 0,0 1,21 7L21,7A2,2 0,0 1,23 5z"/>
+ <path android:fillColor="#919283" android:pathData="M23,11L55,11A2,2 0,0 1,57 13L57,13A2,2 0,0 1,55 15L23,15A2,2 0,0 1,21 13L21,13A2,2 0,0 1,23 11z"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/contrast_dialog.xml b/packages/SystemUI/res/layout/contrast_dialog.xml
new file mode 100644
index 0000000..8e885cf
--- /dev/null
+++ b/packages/SystemUI/res/layout/contrast_dialog.xml
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"/>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <FrameLayout
+ android:id="@+id/contrast_button_standard"
+ android:layout_width="@dimen/contrast_dialog_button_total_size"
+ android:layout_height="@dimen/contrast_dialog_button_total_size"
+ android:background="@drawable/contrast_dialog_button_background">
+
+ <ImageView
+ android:layout_gravity="center"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:src="@drawable/ic_contrast_standard"/>
+ </FrameLayout>
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/contrast_dialog_button_text_spacing"
+ android:gravity="center_horizontal|top"
+ android:textSize="@dimen/contrast_dialog_button_text_size"
+ android:text="@string/quick_settings_contrast_standard"
+ android:textColor="?androidprv:attr/textColorPrimary"/>
+ </LinearLayout>
+
+ <Space
+ android:layout_width="@dimen/contrast_dialog_button_horizontal_spacing"
+ android:layout_height="match_parent" />
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <FrameLayout
+ android:id="@+id/contrast_button_medium"
+ android:layout_width="@dimen/contrast_dialog_button_total_size"
+ android:layout_height="@dimen/contrast_dialog_button_total_size"
+ android:background="@drawable/contrast_dialog_button_background">
+
+ <ImageView
+ android:layout_gravity="center"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:src="@drawable/ic_contrast_medium"/>
+ </FrameLayout>
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/contrast_dialog_button_text_spacing"
+ android:gravity="center_horizontal|top"
+ android:textSize="@dimen/contrast_dialog_button_text_size"
+ android:text="@string/quick_settings_contrast_medium"
+ android:textColor="?androidprv:attr/textColorPrimary"/>
+ </LinearLayout>
+
+ <Space
+ android:layout_width="@dimen/contrast_dialog_button_horizontal_spacing"
+ android:layout_height="match_parent" />
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <FrameLayout
+ android:id="@+id/contrast_button_high"
+ android:layout_width="@dimen/contrast_dialog_button_total_size"
+ android:layout_height="@dimen/contrast_dialog_button_total_size"
+ android:background="@drawable/contrast_dialog_button_background">
+
+ <ImageView
+ android:layout_gravity="center"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:src="@drawable/ic_contrast_high"/>
+
+ </FrameLayout>
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/contrast_dialog_button_text_spacing"
+ android:gravity="center_horizontal|top"
+ android:textSize="@dimen/contrast_dialog_button_text_size"
+ android:text="@string/quick_settings_contrast_high"
+ android:textColor="?androidprv:attr/textColorPrimary"/>
+ </LinearLayout>
+
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"/>
+</LinearLayout>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 2663ffb..714d495 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1735,6 +1735,15 @@
<dimen name="broadcast_dialog_btn_minHeight">44dp</dimen>
<dimen name="broadcast_dialog_margin">16dp</dimen>
+ <!-- Contrast dialog -->
+ <dimen name="contrast_dialog_button_total_size">90dp</dimen>
+ <dimen name="contrast_dialog_button_inner_size">82dp</dimen>
+ <dimen name="contrast_dialog_button_radius">20dp</dimen>
+ <dimen name="contrast_dialog_button_stroke_width">4dp</dimen>
+ <dimen name="contrast_dialog_button_text_size">14sp</dimen>
+ <dimen name="contrast_dialog_button_text_spacing">4dp</dimen>
+ <dimen name="contrast_dialog_button_horizontal_spacing">16dp</dimen>
+
<!-- Shadow for dream overlay clock complication -->
<dimen name="dream_overlay_clock_key_text_shadow_dx">0dp</dimen>
<dimen name="dream_overlay_clock_key_text_shadow_dy">0dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 1dd12ee..f1777f8 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -757,6 +757,15 @@
<!-- QuickSettings: Label for the toggle that controls whether One-handed mode is enabled. [CHAR LIMIT=NONE] -->
<string name="quick_settings_onehanded_label">One-handed mode</string>
+ <!-- QuickSettings: Contrast tile [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_contrast_label">Contrast</string>
+ <!-- QuickSettings: Contrast tile description: standard [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_contrast_standard">Standard</string>
+ <!-- QuickSettings: Contrast tile description: medium [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_contrast_medium">Medium</string>
+ <!-- QuickSettings: Contrast tile description: high [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_contrast_high">High</string>
+
<!--- Title of dialog triggered if the microphone is disabled but an app tried to access it. [CHAR LIMIT=150] -->
<string name="sensor_privacy_start_use_mic_dialog_title">Unblock device microphone?</string>
<!--- Title of dialog triggered if the camera is disabled but an app tried to access it. [CHAR LIMIT=150] -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 8a86fd5..064cea1 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -377,6 +377,10 @@
<item name="android:windowBackground">@android:color/transparent</item>
</style>
+ <style name="Theme.SystemUI.ContrastDialog" parent="@android:style/Theme.DeviceDefault.Dialog">
+ <item name="android:windowBackground">@android:color/transparent</item>
+ </style>
+
<style name="Theme.SystemUI.QuickSettings.Dialog" parent="@android:style/Theme.DeviceDefault.Dialog">
<item name="android:dialogCornerRadius">@dimen/notification_corner_radius</item>
</style>
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 3b9060a..0779653 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -46,10 +46,10 @@
import com.android.systemui.plugins.ClockController
import com.android.systemui.plugins.ClockFaceController
import com.android.systemui.plugins.ClockTickRate
+import com.android.systemui.plugins.WeatherData
import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.plugins.log.LogLevel.DEBUG
import com.android.systemui.shared.regionsampling.RegionSampler
-import com.android.systemui.plugins.WeatherData
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback
import com.android.systemui.statusbar.policy.ConfigurationController
@@ -144,8 +144,10 @@
val currentViewRect = Rect(left, top, right, bottom)
val oldViewRect = Rect(oldLeft, oldTop, oldRight, oldBottom)
- if (currentViewRect.width() != oldViewRect.width() ||
- currentViewRect.height() != oldViewRect.height()) {
+ if (
+ currentViewRect.width() != oldViewRect.width() ||
+ currentViewRect.height() != oldViewRect.height()
+ ) {
updateRegionSampler(view)
}
}
@@ -425,7 +427,7 @@
}
isRunning = true
- when (clockFace.events.tickRate) {
+ when (clockFace.config.tickRate) {
ClockTickRate.PER_MINUTE -> {
/* Handled by KeyguardClockSwitchController */
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 07333f7..9290220 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -40,7 +40,6 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.log.dagger.KeyguardClockLog;
-import com.android.systemui.plugins.ClockAnimations;
import com.android.systemui.plugins.ClockController;
import com.android.systemui.plugins.log.LogBuffer;
import com.android.systemui.plugins.log.LogLevel;
@@ -469,7 +468,7 @@
}
@Nullable
- private ClockController getClock() {
+ public ClockController getClock() {
return mClockEventController.getClock();
}
@@ -535,13 +534,6 @@
}
return ((mCurrentClockSize == LARGE) ? clock.getLargeClock() : clock.getSmallClock())
- .getEvents().getHasCustomWeatherDataDisplay();
- }
-
- /** Gets the animations for the current clock. */
- @Nullable
- public ClockAnimations getClockAnimations() {
- ClockController clock = getClock();
- return clock == null ? null : clock.getAnimations();
+ .getConfig().getHasCustomWeatherDataDisplay();
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index fd55d69..c4df836 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -16,12 +16,13 @@
package com.android.keyguard;
+import android.annotation.Nullable;
import android.graphics.Rect;
import android.util.Slog;
import com.android.keyguard.KeyguardClockSwitch.ClockSize;
import com.android.keyguard.logging.KeyguardLogger;
-import com.android.systemui.plugins.ClockAnimations;
+import com.android.systemui.plugins.ClockController;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
@@ -241,8 +242,9 @@
}
}
- /** Gets the animations for the current clock. */
- public ClockAnimations getClockAnimations() {
- return mKeyguardClockSwitchController.getClockAnimations();
+ /** Gets the current clock controller. */
+ @Nullable
+ public ClockController getClockController() {
+ return mKeyguardClockSwitchController.getClock();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
index 178cda4..ba8e60a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
@@ -306,7 +306,7 @@
lp.width = mSensorBounds.width();
lp.height = mSensorBounds.height();
RectF relativeToView = getBoundsRelativeToView(new RectF(mSensorBounds));
- lp.setMargins(
+ lp.setMarginsRelative(
(int) relativeToView.left,
(int) relativeToView.top,
(int) relativeToView.right,
diff --git a/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialog.kt b/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialog.kt
new file mode 100644
index 0000000..9e15c7e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialog.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.contrast
+
+import android.app.UiModeManager
+import android.app.UiModeManager.ContrastUtils.CONTRAST_LEVEL_HIGH
+import android.app.UiModeManager.ContrastUtils.CONTRAST_LEVEL_MEDIUM
+import android.app.UiModeManager.ContrastUtils.CONTRAST_LEVEL_STANDARD
+import android.app.UiModeManager.ContrastUtils.fromContrastLevel
+import android.app.UiModeManager.ContrastUtils.toContrastLevel
+import android.content.Context
+import android.os.Bundle
+import android.provider.Settings
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.FrameLayout
+import com.android.internal.annotations.VisibleForTesting
+import com.android.systemui.R
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.util.settings.SecureSettings
+import java.util.concurrent.Executor
+
+/** Dialog to select contrast options */
+class ContrastDialog(
+ context: Context?,
+ @Main private val mainExecutor: Executor,
+ private val uiModeManager: UiModeManager,
+ private val userTracker: UserTracker,
+ private val secureSettings: SecureSettings,
+) : SystemUIDialog(context), UiModeManager.ContrastChangeListener {
+
+ @VisibleForTesting lateinit var contrastButtons: Map<Int, FrameLayout>
+ lateinit var dialogView: View
+ @VisibleForTesting var initialContrast: Float = fromContrastLevel(CONTRAST_LEVEL_STANDARD)
+
+ public override fun onCreate(savedInstanceState: Bundle?) {
+ dialogView = LayoutInflater.from(context).inflate(R.layout.contrast_dialog, null)
+ setView(dialogView)
+
+ setTitle(R.string.quick_settings_contrast_label)
+ setNeutralButton(R.string.cancel) { _, _ ->
+ secureSettings.putFloatForUser(
+ Settings.Secure.CONTRAST_LEVEL,
+ initialContrast,
+ userTracker.userId
+ )
+ dismiss()
+ }
+ setPositiveButton(R.string.done) { _, _ -> dismiss() }
+ super.onCreate(savedInstanceState)
+
+ contrastButtons =
+ mapOf(
+ CONTRAST_LEVEL_STANDARD to findViewById(R.id.contrast_button_standard),
+ CONTRAST_LEVEL_MEDIUM to findViewById(R.id.contrast_button_medium),
+ CONTRAST_LEVEL_HIGH to findViewById(R.id.contrast_button_high)
+ )
+
+ contrastButtons.forEach { (contrastLevel, contrastButton) ->
+ contrastButton.setOnClickListener {
+ val contrastValue = fromContrastLevel(contrastLevel)
+ secureSettings.putFloatForUser(
+ Settings.Secure.CONTRAST_LEVEL,
+ contrastValue,
+ userTracker.userId
+ )
+ }
+ }
+
+ initialContrast = uiModeManager.contrast
+ highlightContrast(toContrastLevel(initialContrast))
+ }
+
+ override fun onStart() {
+ super.onStart()
+ uiModeManager.addContrastChangeListener(mainExecutor, this)
+ }
+
+ override fun onStop() {
+ super.onStop()
+ uiModeManager.removeContrastChangeListener(this)
+ }
+
+ override fun onContrastChanged(contrast: Float) {
+ highlightContrast(toContrastLevel(contrast))
+ }
+
+ private fun highlightContrast(contrast: Int) {
+ contrastButtons.forEach { (level, button) -> button.isSelected = level == contrast }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialogActivity.kt b/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialogActivity.kt
new file mode 100644
index 0000000..70d7138
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialogActivity.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.contrast
+
+import android.app.Activity
+import android.app.UiModeManager
+import android.content.Context
+import android.os.Bundle
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.util.settings.SecureSettings
+import java.util.concurrent.Executor
+import javax.inject.Inject
+
+/** Trampoline activity responsible for creating a [ContrastDialog] */
+class ContrastDialogActivity
+@Inject
+constructor(
+ private val context: Context,
+ @Main private val mainExecutor: Executor,
+ private val uiModeManager: UiModeManager,
+ private val userTracker: UserTracker,
+ private val secureSettings: SecureSettings
+) : Activity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ val contrastDialog =
+ ContrastDialog(context, mainExecutor, uiModeManager, userTracker, secureSettings)
+ contrastDialog.show()
+ finish()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
index 3cf26b3..dba353b 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
@@ -19,6 +19,7 @@
import android.app.Activity;
import com.android.systemui.ForegroundServicesDialog;
+import com.android.systemui.contrast.ContrastDialogActivity;
import com.android.systemui.hdmi.HdmiCecSetMenuLanguageActivity;
import com.android.systemui.keyguard.WorkLockActivity;
import com.android.systemui.people.PeopleSpaceActivity;
@@ -73,6 +74,12 @@
@ClassKey(BrightnessDialog.class)
public abstract Activity bindBrightnessDialog(BrightnessDialog activity);
+ /** Inject into ContrastDialogActivity. */
+ @Binds
+ @IntoMap
+ @ClassKey(ContrastDialogActivity.class)
+ public abstract Activity bindContrastDialogActivity(ContrastDialogActivity activity);
+
/** Inject into UsbDebuggingActivity. */
@Binds
@IntoMap
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 503b6fc..0bc8506 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -285,7 +285,7 @@
/** Enables Font Scaling Quick Settings tile */
// TODO(b/269341316): Tracking Bug
@JvmField
- val ENABLE_FONT_SCALING_TILE = unreleasedFlag(509, "enable_font_scaling_tile", teamfood = true)
+ val ENABLE_FONT_SCALING_TILE = releasedFlag(509, "enable_font_scaling_tile")
/** Enables new QS Edit Mode visual refresh */
// TODO(b/269787742): Tracking Bug
@@ -417,7 +417,7 @@
// TODO(b/273509374): Tracking Bug
@JvmField
- val ALWAYS_SHOW_HOME_CONTROLS_ON_DREAMS = unreleasedFlag(1006,
+ val ALWAYS_SHOW_HOME_CONTROLS_ON_DREAMS = releasedFlag(1006,
"always_show_home_controls_on_dreams")
// 1100 - windowing
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index b1efdd7..c102c5b5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -2856,14 +2856,14 @@
+ " wasShowing=" + wasShowing);
}
+ mKeyguardUnlockAnimationControllerLazy.get()
+ .notifyFinishedKeyguardExitAnimation(cancelled);
finishSurfaceBehindRemoteAnimation(cancelled);
// Dispatch the callback on animation finishes.
mUpdateMonitor.dispatchKeyguardDismissAnimationFinished();
});
- mKeyguardUnlockAnimationControllerLazy.get().notifyFinishedKeyguardExitAnimation(
- cancelled);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
index 8f1c904..30ee147 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
@@ -63,6 +63,10 @@
override fun onStateChanged(newState: Int) {
refreshMediaPosition()
}
+
+ override fun onDozingChanged(isDozing: Boolean) {
+ refreshMediaPosition()
+ }
}
)
configurationController.addCallback(
@@ -198,7 +202,8 @@
mediaHost.visible &&
!bypassController.bypassEnabled &&
keyguardOrUserSwitcher &&
- allowMediaPlayerOnLockScreen
+ allowMediaPlayerOnLockScreen &&
+ shouldBeVisibleForSplitShade()
if (visible) {
showMediaPlayer()
} else {
@@ -206,6 +211,19 @@
}
}
+ private fun shouldBeVisibleForSplitShade(): Boolean {
+ if (!useSplitShade) {
+ return true
+ }
+ // We have to explicitly hide media for split shade when on AOD, as it is a child view of
+ // keyguard status view, and nothing hides keyguard status view on AOD.
+ // When using the double-line clock, it is not an issue, as media gets implicitly hidden
+ // by the clock. This is not the case for single-line clock though.
+ // For single shade, we don't need to do it, because media is a child of NSSL, which already
+ // gets hidden on AOD.
+ return !statusBarStateController.isDozing
+ }
+
private fun showMediaPlayer() {
if (useSplitShade) {
setVisibility(splitShadeContainer, View.VISIBLE)
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 9928c4f..f50a7a8 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -205,7 +205,8 @@
&& mController.isSubStatusSupported()
&& mController.isAdvancedLayoutSupported() && device.hasSubtext()) {
boolean isActiveWithOngoingSession =
- (device.hasOngoingSession() && currentlyConnected);
+ (device.hasOngoingSession() && (currentlyConnected || isDeviceIncluded(
+ mController.getSelectedMediaDevice(), device)));
boolean isHost = device.isHostForOngoingSession()
&& isActiveWithOngoingSession;
if (isHost) {
@@ -224,10 +225,17 @@
if (isActiveWithOngoingSession) {
//Selected device which has ongoing session, disable seekbar since we
//only allow volume control on Host
- initSeekbar(device, isCurrentSeekbarInvisible);
mCurrentActivePosition = position;
}
- setUpDeviceIcon(device);
+ boolean showSeekbar =
+ (!device.hasOngoingSession() && currentlyConnected);
+ if (showSeekbar) {
+ updateTitleIcon(R.drawable.media_output_icon_volume,
+ mController.getColorItemContent());
+ initSeekbar(device, isCurrentSeekbarInvisible);
+ } else {
+ setUpDeviceIcon(device);
+ }
mSubTitleText.setText(device.getSubtextString());
Drawable deviceStatusIcon =
device.hasOngoingSession() ? mContext.getDrawable(
@@ -241,8 +249,8 @@
updateTwoLineLayoutContentAlpha(
updateClickActionBasedOnSelectionBehavior(device)
? DEVICE_CONNECTED_ALPHA : DEVICE_DISCONNECTED_ALPHA);
- setTwoLineLayout(device, isActiveWithOngoingSession /* bFocused */,
- isActiveWithOngoingSession /* showSeekBar */,
+ setTwoLineLayout(device, currentlyConnected /* bFocused */,
+ showSeekbar /* showSeekBar */,
false /* showProgressBar */, true /* showSubtitle */,
deviceStatusIcon != null /* showStatus */,
isActiveWithOngoingSession /* isFakeActive */);
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 731bb2f..73ab5272 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -270,10 +270,10 @@
final Drawable backgroundDrawable;
if (mController.isAdvancedLayoutSupported() && mController.isSubStatusSupported()) {
backgroundDrawable = mContext.getDrawable(
- showSeekBar ? R.drawable.media_output_item_background_active
+ showSeekBar || isFakeActive ? R.drawable.media_output_item_background_active
: R.drawable.media_output_item_background).mutate();
backgroundDrawable.setTint(
- showSeekBar ? mController.getColorConnectedItemBackground()
+ showSeekBar || isFakeActive ? mController.getColorConnectedItemBackground()
: mController.getColorItemBackground());
mIconAreaLayout.setBackgroundTintList(
ColorStateList.valueOf(showProgressBar || isFakeActive
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index b7243ae9..79d3b26 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -162,7 +162,7 @@
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.navigationbar.NavigationBarView;
import com.android.systemui.navigationbar.NavigationModeController;
-import com.android.systemui.plugins.ClockAnimations;
+import com.android.systemui.plugins.ClockController;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.FalsingManager.FalsingTapListener;
import com.android.systemui.plugins.qs.QS;
@@ -1627,9 +1627,9 @@
transition.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
transition.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
- ClockAnimations clockAnims = mKeyguardStatusViewController.getClockAnimations();
- boolean customClockAnimation = clockAnims != null
- && clockAnims.getHasCustomPositionUpdatedAnimation();
+ ClockController clock = mKeyguardStatusViewController.getClockController();
+ boolean customClockAnimation = clock != null
+ && clock.getConfig().getHasCustomPositionUpdatedAnimation();
if (mFeatureFlags.isEnabled(Flags.STEP_CLOCK_ANIMATION) && customClockAnimation) {
// Find the clock, so we can exclude it from this transition.
@@ -5159,12 +5159,12 @@
Rect to = (Rect) endValues.values.get(PROP_BOUNDS);
anim.addUpdateListener(animation -> {
- ClockAnimations clockAnims = mController.getClockAnimations();
- if (clockAnims == null) {
+ ClockController clock = mController.getClockController();
+ if (clock == null) {
return;
}
- clockAnims.onPositionUpdated(from, to, animation.getAnimatedFraction());
+ clock.getAnimations().onPositionUpdated(from, to, animation.getAnimatedFraction());
});
return anim;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
index 0fd007c..62bc27f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
@@ -170,7 +170,10 @@
if (networkTypeIconGroup.dataContentDescription != 0)
ContentDescription.Resource(networkTypeIconGroup.dataContentDescription)
else null
- val icon = Icon.Resource(networkTypeIconGroup.dataType, desc)
+ val icon =
+ if (networkTypeIconGroup.dataType != 0)
+ Icon.Resource(networkTypeIconGroup.dataType, desc)
+ else null
return@combine when {
!shouldShow -> null
else -> icon
diff --git a/packages/SystemUI/src/com/android/systemui/util/service/ObservableServiceConnection.java b/packages/SystemUI/src/com/android/systemui/util/service/ObservableServiceConnection.java
index c6da55c..968dcc9 100644
--- a/packages/SystemUI/src/com/android/systemui/util/service/ObservableServiceConnection.java
+++ b/packages/SystemUI/src/com/android/systemui/util/service/ObservableServiceConnection.java
@@ -25,6 +25,7 @@
import android.util.Log;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.settings.UserTracker;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -108,6 +109,7 @@
private final Context mContext;
private final Intent mServiceIntent;
+ private final UserTracker mUserTracker;
private final int mFlags;
private final Executor mExecutor;
private final ServiceTransformer<T> mTransformer;
@@ -127,10 +129,12 @@
*/
@Inject
public ObservableServiceConnection(Context context, Intent serviceIntent,
+ UserTracker userTracker,
@Main Executor executor,
ServiceTransformer<T> transformer) {
mContext = context;
mServiceIntent = serviceIntent;
+ mUserTracker = userTracker;
mFlags = Context.BIND_AUTO_CREATE;
mExecutor = executor;
mTransformer = transformer;
@@ -145,7 +149,8 @@
public boolean bind() {
boolean bindResult = false;
try {
- bindResult = mContext.bindService(mServiceIntent, mFlags, mExecutor, this);
+ bindResult = mContext.bindServiceAsUser(mServiceIntent, this, mFlags,
+ mUserTracker.getUserHandle());
} catch (SecurityException e) {
Log.d(TAG, "Could not bind to service", e);
mContext.unbindService(this);
@@ -228,11 +233,13 @@
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
- if (DEBUG) {
- Log.d(TAG, "onServiceConnected");
- }
- mProxy = mTransformer.convert(service);
- applyToCallbacksLocked(callback -> callback.onConnected(this, mProxy));
+ mExecutor.execute(() -> {
+ if (DEBUG) {
+ Log.d(TAG, "onServiceConnected");
+ }
+ mProxy = mTransformer.convert(service);
+ applyToCallbacksLocked(callback -> callback.onConnected(this, mProxy));
+ });
}
private void applyToCallbacksLocked(Consumer<Callback<T>> applicator) {
@@ -250,16 +257,16 @@
@Override
public void onServiceDisconnected(ComponentName name) {
- onDisconnected(DISCONNECT_REASON_DISCONNECTED);
+ mExecutor.execute(() -> onDisconnected(DISCONNECT_REASON_DISCONNECTED));
}
@Override
public void onBindingDied(ComponentName name) {
- onDisconnected(DISCONNECT_REASON_DISCONNECTED);
+ mExecutor.execute(() -> onDisconnected(DISCONNECT_REASON_BINDING_DIED));
}
@Override
public void onNullBinding(ComponentName name) {
- onDisconnected(DISCONNECT_REASON_NULL_BINDING);
+ mExecutor.execute(() -> onDisconnected(DISCONNECT_REASON_NULL_BINDING));
}
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index 480b8f9..a9920ec7 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -32,6 +32,7 @@
import com.android.systemui.plugins.ClockController
import com.android.systemui.plugins.ClockEvents
import com.android.systemui.plugins.ClockFaceController
+import com.android.systemui.plugins.ClockFaceConfig
import com.android.systemui.plugins.ClockFaceEvents
import com.android.systemui.plugins.ClockTickRate
import com.android.systemui.plugins.log.LogBuffer
@@ -101,8 +102,10 @@
whenever(largeClockController.events).thenReturn(largeClockEvents)
whenever(clock.events).thenReturn(events)
whenever(clock.animations).thenReturn(animations)
- whenever(smallClockEvents.tickRate).thenReturn(ClockTickRate.PER_MINUTE)
- whenever(largeClockEvents.tickRate).thenReturn(ClockTickRate.PER_MINUTE)
+ whenever(smallClockController.config)
+ .thenReturn(ClockFaceConfig(tickRate = ClockTickRate.PER_MINUTE))
+ whenever(largeClockController.config)
+ .thenReturn(ClockFaceConfig(tickRate = ClockTickRate.PER_MINUTE))
repository = FakeKeyguardRepository()
bouncerRepository = FakeKeyguardBouncerRepository()
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index b15ac39..2f627cb 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -315,8 +315,8 @@
}
@Test
- public void testGetClockAnimationsForwardsToClock() {
- assertEquals(mClockAnimations, mController.getClockAnimations());
+ public void testGetClock_ForwardsToClock() {
+ assertEquals(mClockController, mController.getClock());
}
@Test
@@ -367,9 +367,9 @@
}
@Test
- public void testGetClockAnimations_nullClock_returnsNull() {
+ public void testGetClock_nullClock_returnsNull() {
when(mClockEventController.getClock()).thenReturn(null);
- assertNull(mController.getClockAnimations());
+ assertNull(mController.getClock());
}
private void verifyAttachment(VerificationMode times) {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
index 7144914..48f7d92 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewControllerTest.java
@@ -16,17 +16,17 @@
package com.android.keyguard;
+import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.graphics.Rect;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import com.android.keyguard.logging.KeyguardLogger;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.plugins.ClockAnimations;
+import com.android.systemui.plugins.ClockController;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -118,14 +118,10 @@
}
@Test
- public void getClockAnimations_forwardsToClockSwitch() {
- ClockAnimations mockClockAnimations = mock(ClockAnimations.class);
- when(mKeyguardClockSwitchController.getClockAnimations()).thenReturn(mockClockAnimations);
+ public void getClock_forwardsToClockSwitch() {
+ ClockController mockClock = mock(ClockController.class);
+ when(mKeyguardClockSwitchController.getClock()).thenReturn(mockClock);
- Rect r1 = new Rect(1, 2, 3, 4);
- Rect r2 = new Rect(5, 6, 7, 8);
- mController.getClockAnimations().onPositionUpdated(r1, r2, 0.3f);
-
- verify(mockClockAnimations).onPositionUpdated(r1, r2, 0.3f);
+ assertEquals(mockClock, mController.getClockController());
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/contrast/ContrastDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/contrast/ContrastDialogTest.kt
new file mode 100644
index 0000000..7753197
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/contrast/ContrastDialogTest.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.contrast
+
+import android.app.UiModeManager
+import android.app.UiModeManager.ContrastUtils.fromContrastLevel
+import android.os.Looper
+import android.provider.Settings
+import android.testing.AndroidTestingRunner
+import android.widget.FrameLayout
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.settings.SecureSettings
+import com.google.common.util.concurrent.MoreExecutors
+import java.util.concurrent.Executor
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.eq
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+/** Test the behaviour of buttons of the [ContrastDialog]. */
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class ContrastDialogTest : SysuiTestCase() {
+
+ private lateinit var mainExecutor: Executor
+ private lateinit var contrastDialog: ContrastDialog
+ @Mock private lateinit var mockUiModeManager: UiModeManager
+ @Mock private lateinit var mockUserTracker: UserTracker
+ @Mock private lateinit var mockSecureSettings: SecureSettings
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ mainExecutor = MoreExecutors.directExecutor()
+ whenever(mockUserTracker.userId).thenReturn(context.userId)
+ }
+
+ @Test
+ fun testClickButtons_putsContrastInSettings() {
+ if (Looper.myLooper() == null) Looper.prepare()
+ contrastDialog =
+ ContrastDialog(
+ context,
+ mainExecutor,
+ mockUiModeManager,
+ mockUserTracker,
+ mockSecureSettings
+ )
+ contrastDialog.show()
+ try {
+ contrastDialog.contrastButtons.forEach {
+ (contrastLevel: Int, clickedButton: FrameLayout) ->
+ clickedButton.performClick()
+ verify(mockSecureSettings)
+ .putFloatForUser(
+ eq(Settings.Secure.CONTRAST_LEVEL),
+ eq(fromContrastLevel(contrastLevel)),
+ eq(context.userId)
+ )
+ }
+ } finally {
+ contrastDialog.dismiss()
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsFavoritingActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsFavoritingActivityTest.kt
index 6884616..f4cc8bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsFavoritingActivityTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsFavoritingActivityTest.kt
@@ -60,6 +60,12 @@
}
val TEST_STRUCTURE: CharSequence = "TestStructure"
val TEST_APP: CharSequence = "TestApp"
+
+ private fun View.waitForPost() {
+ val latch = CountDownLatch(1)
+ post(latch::countDown)
+ latch.await()
+ }
}
@Main private val executor: Executor = MoreExecutors.directExecutor()
@@ -140,7 +146,10 @@
val rearrangeButton = requireViewById<Button>(R.id.rearrange)
assertThat(rearrangeButton.visibility).isEqualTo(View.VISIBLE)
assertThat(rearrangeButton.isEnabled).isFalse()
- assertThat(requireViewById<Button>(R.id.other_apps).visibility).isEqualTo(View.GONE)
+
+ val otherAppsButton = requireViewById<Button>(R.id.other_apps)
+ otherAppsButton.waitForPost()
+ assertThat(otherAppsButton.visibility).isEqualTo(View.GONE)
}
}
@@ -160,7 +169,10 @@
val rearrangeButton = requireViewById<Button>(R.id.rearrange)
assertThat(rearrangeButton.visibility).isEqualTo(View.GONE)
assertThat(rearrangeButton.isEnabled).isFalse()
- assertThat(requireViewById<Button>(R.id.other_apps).visibility).isEqualTo(View.VISIBLE)
+
+ val otherAppsButton = requireViewById<Button>(R.id.other_apps)
+ otherAppsButton.waitForPost()
+ assertThat(otherAppsButton.visibility).isEqualTo(View.VISIBLE)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt
index 2026006..b40ebc9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt
@@ -24,12 +24,14 @@
import android.view.View.VISIBLE
import android.widget.FrameLayout
import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.notification.stack.MediaContainerView
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.animation.UniqueObjectHostView
+import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.settings.FakeSettings
import com.android.systemui.utils.os.FakeHandler
import com.google.common.truth.Truth.assertThat
@@ -39,8 +41,9 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
+import org.mockito.Mockito.any
+import org.mockito.Mockito.doAnswer
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
@SmallTest
@@ -61,9 +64,16 @@
private lateinit var keyguardMediaController: KeyguardMediaController
private lateinit var testableLooper: TestableLooper
private lateinit var fakeHandler: FakeHandler
+ private lateinit var statusBarStateListener: StatusBarStateController.StateListener
@Before
fun setup() {
+ doAnswer {
+ statusBarStateListener = it.arguments[0] as StatusBarStateController.StateListener
+ return@doAnswer Unit
+ }
+ .whenever(statusBarStateController)
+ .addCallback(any(StatusBarStateController.StateListener::class.java))
// default state is positive, media should show up
whenever(mediaHost.visible).thenReturn(true)
whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
@@ -170,4 +180,31 @@
fun testMediaHost_expandedPlayer() {
verify(mediaHost).expansion = MediaHostState.EXPANDED
}
+
+ @Test
+ fun dozing_inSplitShade_mediaIsHidden() {
+ val splitShadeContainer = FrameLayout(context)
+ keyguardMediaController.attachSplitShadeContainer(splitShadeContainer)
+ keyguardMediaController.useSplitShade = true
+
+ setDozing()
+
+ assertThat(splitShadeContainer.visibility).isEqualTo(GONE)
+ }
+
+ @Test
+ fun dozing_inSingleShade_mediaIsVisible() {
+ val splitShadeContainer = FrameLayout(context)
+ keyguardMediaController.attachSplitShadeContainer(splitShadeContainer)
+ keyguardMediaController.useSplitShade = false
+
+ setDozing()
+
+ assertThat(mediaContainerView.visibility).isEqualTo(VISIBLE)
+ }
+
+ private fun setDozing() {
+ whenever(statusBarStateController.isDozing).thenReturn(true)
+ statusBarStateListener.onDozingChanged(true)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
index 17d8799..7f7952f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
@@ -532,7 +532,7 @@
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
- assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mStatusIcon.getVisibility()).isEqualTo(View.VISIBLE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
index 8ea8f87..1593e5c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
@@ -20,6 +20,7 @@
import com.android.settingslib.AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH
import com.android.settingslib.AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH_NONE
import com.android.settingslib.mobile.TelephonyIcons.THREE_G
+import com.android.settingslib.mobile.TelephonyIcons.UNKNOWN
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
@@ -343,7 +344,7 @@
fun networkType_alwaysShow_shownEvenWhenDisabled() =
testScope.runTest {
interactor.setIconGroup(THREE_G)
- interactor.setIsDataEnabled(true)
+ interactor.setIsDataEnabled(false)
interactor.alwaysShowDataRatIcon.value = true
var latest: Icon? = null
@@ -400,6 +401,21 @@
}
@Test
+ fun networkType_alwaysShow_notShownWhenInvalidDataTypeIcon() =
+ testScope.runTest {
+ // The UNKNOWN icon group doesn't have a valid data type icon ID
+ interactor.setIconGroup(UNKNOWN)
+ interactor.alwaysShowDataRatIcon.value = true
+
+ var latest: Icon? = null
+ val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
+
+ assertThat(latest).isNull()
+
+ job.cancel()
+ }
+
+ @Test
fun `network type - alwaysShow - shown when not default`() =
testScope.runTest {
interactor.setIconGroup(THREE_G)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java
index f9bfafc..766a5ce 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java
@@ -29,12 +29,15 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.UserInfo;
import android.os.IBinder;
+import android.os.UserHandle;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.settings.FakeUserTracker;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -44,6 +47,7 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.List;
import java.util.Objects;
@SmallTest
@@ -93,15 +97,22 @@
FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
+ private FakeUserTracker mUserTracker;
+
+ private static final int MAIN_USER_ID = 10;
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ mUserTracker = new FakeUserTracker();
+ // Set the main user as the current user.
+ mUserTracker.set(List.of(new UserInfo(MAIN_USER_ID, "main", UserInfo.FLAG_MAIN)), 0);
}
@Test
public void testConnect() {
ObservableServiceConnection<Foo> connection = new ObservableServiceConnection<>(mContext,
- mIntent, mExecutor, mTransformer);
+ mIntent, mUserTracker, mExecutor, mTransformer);
// Register twice to ensure only one callback occurs.
connection.addCallback(mCallback);
connection.addCallback(mCallback);
@@ -121,15 +132,16 @@
@Test
public void testDisconnect() {
ObservableServiceConnection<Foo> connection = new ObservableServiceConnection<>(mContext,
- mIntent, mExecutor, mTransformer);
+ mIntent, mUserTracker, mExecutor, mTransformer);
connection.addCallback(mCallback);
connection.onServiceDisconnected(mComponentName);
+ mExecutor.runAllReady();
// Disconnects before binds should be ignored.
verify(mCallback, never()).onDisconnected(eq(connection), anyInt());
- when(mContext.bindService(eq(mIntent), anyInt(), eq(mExecutor), eq(connection)))
- .thenReturn(true);
+ when(mContext.bindServiceAsUser(eq(mIntent), eq(connection), anyInt(),
+ eq(UserHandle.of(MAIN_USER_ID)))).thenReturn(true);
connection.bind();
connection.onServiceDisconnected(mComponentName);
@@ -151,15 +163,16 @@
@Test
public void testUnbind() {
ObservableServiceConnection<Foo> connection = new ObservableServiceConnection<>(mContext,
- mIntent, mExecutor, mTransformer);
+ mIntent, mUserTracker, mExecutor, mTransformer);
connection.addCallback(mCallback);
connection.onServiceDisconnected(mComponentName);
+ mExecutor.runAllReady();
// Disconnects before binds should be ignored.
verify(mCallback, never()).onDisconnected(eq(connection), anyInt());
- when(mContext.bindService(eq(mIntent), anyInt(), eq(mExecutor), eq(connection)))
- .thenReturn(true);
+ when(mContext.bindServiceAsUser(eq(mIntent), eq(connection), anyInt(),
+ eq(UserHandle.of(MAIN_USER_ID)))).thenReturn(true);
connection.bind();
mExecutor.runAllReady();
@@ -175,10 +188,11 @@
@Test
public void testBindServiceThrowsError() {
ObservableServiceConnection<Foo> connection = new ObservableServiceConnection<>(mContext,
- mIntent, mExecutor, mTransformer);
+ mIntent, mUserTracker, mExecutor, mTransformer);
connection.addCallback(mCallback);
- when(mContext.bindService(eq(mIntent), anyInt(), eq(mExecutor), eq(connection)))
+ when(mContext.bindServiceAsUser(eq(mIntent), eq(connection), anyInt(),
+ eq(UserHandle.of(MAIN_USER_ID))))
.thenThrow(new SecurityException());
// Verify that the exception was caught and that bind returns false, and we properly
diff --git a/services/autofill/java/com/android/server/autofill/FieldClassificationEventLogger.java b/services/autofill/java/com/android/server/autofill/FieldClassificationEventLogger.java
new file mode 100644
index 0000000..ffb4632
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/FieldClassificationEventLogger.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.autofill;
+
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FIELD_CLASSIFICATION_EVENT_REPORTED;
+import static com.android.server.autofill.Helper.sVerbose;
+
+import android.util.Slog;
+
+import com.android.internal.util.FrameworkStatsLog;
+
+import java.util.Optional;
+
+/**
+ * Helper class to log Field Classification stats.
+ */
+public final class FieldClassificationEventLogger {
+ private static final String TAG = "FieldClassificationEventLogger";
+ private Optional<FieldClassificationEventInternal> mEventInternal;
+
+ private FieldClassificationEventLogger() {
+ mEventInternal = Optional.empty();
+ }
+
+ /**
+ * A factory constructor to create FieldClassificationEventLogger.
+ */
+ public static FieldClassificationEventLogger createLogger() {
+ return new FieldClassificationEventLogger();
+ }
+
+ /**
+ * Reset mEventInternal before logging for a new request. It shall be called for each
+ * FieldClassification request.
+ */
+ public void startNewLogForRequest() {
+ if (!mEventInternal.isEmpty()) {
+ Slog.w(TAG, "FieldClassificationEventLogger is not empty before starting for a new "
+ + "request");
+ }
+ mEventInternal = Optional.of(new FieldClassificationEventInternal());
+ }
+
+ /**
+ * Set latency as long as mEventInternal presents.
+ */
+ public void maybeSetLatencyMillis(long timestamp) {
+ mEventInternal.ifPresent(event -> {
+ event.mLatencyClassificationRequestMillis = timestamp;
+ });
+ }
+
+ /**
+ * Log an AUTOFILL_FIELD_CLASSIFICATION_EVENT_REPORTED event.
+ */
+ public void logAndEndEvent() {
+ if (!mEventInternal.isPresent()) {
+ Slog.w(TAG, "Shouldn't be logging AutofillFieldClassificationEventInternal again for "
+ + "same event");
+ return;
+ }
+ FieldClassificationEventInternal event = mEventInternal.get();
+ if (sVerbose) {
+ Slog.v(TAG, "Log AutofillFieldClassificationEventReported:"
+ + " mLatencyClassificationRequestMillis="
+ + event.mLatencyClassificationRequestMillis);
+ }
+ FrameworkStatsLog.write(
+ AUTOFILL_FIELD_CLASSIFICATION_EVENT_REPORTED,
+ event.mLatencyClassificationRequestMillis);
+ mEventInternal = Optional.empty();
+ }
+
+ private static final class FieldClassificationEventInternal {
+ long mLatencyClassificationRequestMillis = -1;
+
+ FieldClassificationEventInternal() {
+ }
+ }
+}
diff --git a/services/autofill/java/com/android/server/autofill/FillResponseEventLogger.java b/services/autofill/java/com/android/server/autofill/FillResponseEventLogger.java
index 6b8246c..8f2ab71 100644
--- a/services/autofill/java/com/android/server/autofill/FillResponseEventLogger.java
+++ b/services/autofill/java/com/android/server/autofill/FillResponseEventLogger.java
@@ -17,16 +17,16 @@
package com.android.server.autofill;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED;
-import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DISPLAY_PRESENTATION_TYPE__UNKNOWN_AUTOFILL_DISPLAY_PRESENTATION_TYPE;
-import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DISPLAY_PRESENTATION_TYPE__MENU;
-import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DISPLAY_PRESENTATION_TYPE__INLINE;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DISPLAY_PRESENTATION_TYPE__DIALOG;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DISPLAY_PRESENTATION_TYPE__INLINE;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DISPLAY_PRESENTATION_TYPE__MENU;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DISPLAY_PRESENTATION_TYPE__UNKNOWN_AUTOFILL_DISPLAY_PRESENTATION_TYPE;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_FAILURE;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_RESULT_UNKNOWN;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_SUCCESS;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_TYPE__AUTHENTICATION_TYPE_UNKNOWN;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_TYPE__DATASET_AUTHENTICATION;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_TYPE__FULL_AUTHENTICATION;
-import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_RESULT_UNKNOWN;
-import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_SUCCESS;
-import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_FAILURE;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__RESPONSE_STATUS__RESPONSE_STATUS_CANCELLED;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__RESPONSE_STATUS__RESPONSE_STATUS_FAILURE;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__RESPONSE_STATUS__RESPONSE_STATUS_SESSION_DESTROYED;
@@ -37,12 +37,7 @@
import android.annotation.IntDef;
import android.annotation.Nullable;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.provider.Settings;
import android.service.autofill.Dataset;
-import android.text.TextUtils;
import android.util.Slog;
import android.view.autofill.AutofillId;
@@ -154,6 +149,9 @@
// succeeded.
public static final int AVAILABLE_COUNT_WHEN_FILL_REQUEST_FAILED_OR_TIMEOUT = -1;
+ // Log a magic number to indicate that the FillResponse contains a saveTriggerId.
+ public static final int HAVE_SAVE_TRIGGER_ID = 1;
+
private final int mSessionId;
private Optional<FillResponseEventInternal> mEventInternal;
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFieldClassificationService.java b/services/autofill/java/com/android/server/autofill/RemoteFieldClassificationService.java
index 99a2291..feae56e 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFieldClassificationService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFieldClassificationService.java
@@ -30,6 +30,7 @@
import android.content.pm.ServiceInfo;
import android.os.ICancellationSignal;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.service.assist.classification.FieldClassificationRequest;
import android.service.assist.classification.FieldClassificationResponse;
import android.service.assist.classification.FieldClassificationService;
@@ -132,7 +133,7 @@
public void onFieldClassificationRequest(@NonNull FieldClassificationRequest request,
FieldClassificationServiceCallbacks fieldClassificationServiceCallbacks) {
-
+ final long startTime = SystemClock.elapsedRealtime();
if (sVerbose) {
Slog.v(TAG, "onFieldClassificationRequest request:" + request);
}
@@ -144,6 +145,7 @@
new IFieldClassificationCallback.Stub() {
@Override
public void onCancellable(ICancellationSignal cancellation) {
+ logLatency(startTime);
if (sDebug) {
Log.d(TAG, "onCancellable");
}
@@ -151,15 +153,15 @@
@Override
public void onSuccess(FieldClassificationResponse response) {
+ logLatency(startTime);
if (sDebug) {
Log.d(TAG, "onSuccess Response: " + response);
}
- fieldClassificationServiceCallbacks
- .onClassificationRequestSuccess(response);
}
@Override
public void onFailure() {
+ logLatency(startTime);
if (sDebug) {
Log.d(TAG, "onFailure");
}
@@ -174,4 +176,12 @@
public void cancel() throws RemoteException {}
}));
}
+
+ private void logLatency(long startTime) {
+ final FieldClassificationEventLogger logger = FieldClassificationEventLogger.createLogger();
+ logger.startNewLogForRequest();
+ logger.maybeSetLatencyMillis(
+ SystemClock.elapsedRealtime() - startTime);
+ logger.logAndEndEvent();
+ }
}
diff --git a/services/autofill/java/com/android/server/autofill/SaveEventLogger.java b/services/autofill/java/com/android/server/autofill/SaveEventLogger.java
index 4b7d5bd..e5435c2 100644
--- a/services/autofill/java/com/android/server/autofill/SaveEventLogger.java
+++ b/services/autofill/java/com/android/server/autofill/SaveEventLogger.java
@@ -23,8 +23,10 @@
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_NONE;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_NO_SAVE_INFO;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_NO_VALUE_CHANGED;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_SESSION_DESTROYED;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_UNKNOWN;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_WITH_DELAY_SAVE_FLAG;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_WITH_DONT_SAVE_ON_FINISH_FLAG;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_SHOWN_REASON__SAVE_UI_SHOWN_REASON_OPTIONAL_ID_CHANGE;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_SHOWN_REASON__SAVE_UI_SHOWN_REASON_REQUIRED_ID_CHANGE;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_SHOWN_REASON__SAVE_UI_SHOWN_REASON_TRIGGER_ID_SET;
@@ -32,11 +34,6 @@
import static com.android.server.autofill.Helper.sVerbose;
import android.annotation.IntDef;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.provider.Settings;
-import android.text.TextUtils;
import android.util.Slog;
import com.android.internal.util.FrameworkStatsLog;
@@ -74,10 +71,12 @@
NO_SAVE_REASON_NONE,
NO_SAVE_REASON_NO_SAVE_INFO,
NO_SAVE_REASON_WITH_DELAY_SAVE_FLAG,
+ NO_SAVE_REASON_WITH_DONT_SAVE_ON_FINISH_FLAG,
NO_SAVE_REASON_HAS_EMPTY_REQUIRED,
NO_SAVE_REASON_NO_VALUE_CHANGED,
NO_SAVE_REASON_FIELD_VALIDATION_FAILED,
- NO_SAVE_REASON_DATASET_MATCH
+ NO_SAVE_REASON_DATASET_MATCH,
+ NO_SAVE_REASON_SESSION_DESTROYED
})
@Retention(RetentionPolicy.SOURCE)
public @interface SaveUiNotShownReason {
@@ -108,6 +107,10 @@
AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_FIELD_VALIDATION_FAILED;
public static final int NO_SAVE_REASON_DATASET_MATCH =
AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_DATASET_MATCH;
+ public static final int NO_SAVE_REASON_SESSION_DESTROYED =
+ AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_SESSION_DESTROYED;
+ public static final int NO_SAVE_REASON_WITH_DONT_SAVE_ON_FINISH_FLAG =
+ AUTOFILL_SAVE_EVENT_REPORTED__SAVE_UI_NOT_SHOWN_REASON__NO_SAVE_REASON_WITH_DONT_SAVE_ON_FINISH_FLAG;
private final int mSessionId;
private Optional<SaveEventInternal> mEventInternal;
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index fe2a3ba..8d039fc 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -45,6 +45,7 @@
import static com.android.server.autofill.FillRequestEventLogger.TRIGGER_REASON_PRE_TRIGGER;
import static com.android.server.autofill.FillRequestEventLogger.TRIGGER_REASON_SERVED_FROM_CACHED_RESPONSE;
import static com.android.server.autofill.FillResponseEventLogger.AVAILABLE_COUNT_WHEN_FILL_REQUEST_FAILED_OR_TIMEOUT;
+import static com.android.server.autofill.FillResponseEventLogger.HAVE_SAVE_TRIGGER_ID;
import static com.android.server.autofill.FillResponseEventLogger.RESPONSE_STATUS_FAILURE;
import static com.android.server.autofill.FillResponseEventLogger.RESPONSE_STATUS_SESSION_DESTROYED;
import static com.android.server.autofill.FillResponseEventLogger.RESPONSE_STATUS_SUCCESS;
@@ -58,8 +59,22 @@
import static com.android.server.autofill.PresentationStatsEventLogger.NOT_SHOWN_REASON_NO_FOCUS;
import static com.android.server.autofill.PresentationStatsEventLogger.NOT_SHOWN_REASON_REQUEST_FAILED;
import static com.android.server.autofill.PresentationStatsEventLogger.NOT_SHOWN_REASON_REQUEST_TIMEOUT;
+import static com.android.server.autofill.PresentationStatsEventLogger.NOT_SHOWN_REASON_SESSION_COMMITTED_PREMATURELY;
import static com.android.server.autofill.PresentationStatsEventLogger.NOT_SHOWN_REASON_VIEW_CHANGED;
import static com.android.server.autofill.PresentationStatsEventLogger.NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED;
+import static com.android.server.autofill.SaveEventLogger.NO_SAVE_REASON_DATASET_MATCH;
+import static com.android.server.autofill.SaveEventLogger.NO_SAVE_REASON_FIELD_VALIDATION_FAILED;
+import static com.android.server.autofill.SaveEventLogger.NO_SAVE_REASON_HAS_EMPTY_REQUIRED;
+import static com.android.server.autofill.SaveEventLogger.NO_SAVE_REASON_NONE;
+import static com.android.server.autofill.SaveEventLogger.NO_SAVE_REASON_NO_SAVE_INFO;
+import static com.android.server.autofill.SaveEventLogger.NO_SAVE_REASON_NO_VALUE_CHANGED;
+import static com.android.server.autofill.SaveEventLogger.NO_SAVE_REASON_SESSION_DESTROYED;
+import static com.android.server.autofill.SaveEventLogger.NO_SAVE_REASON_WITH_DELAY_SAVE_FLAG;
+import static com.android.server.autofill.SaveEventLogger.NO_SAVE_REASON_WITH_DONT_SAVE_ON_FINISH_FLAG;
+import static com.android.server.autofill.SaveEventLogger.SAVE_UI_SHOWN_REASON_OPTIONAL_ID_CHANGE;
+import static com.android.server.autofill.SaveEventLogger.SAVE_UI_SHOWN_REASON_REQUIRED_ID_CHANGE;
+import static com.android.server.autofill.SaveEventLogger.SAVE_UI_SHOWN_REASON_TRIGGER_ID_SET;
+import static com.android.server.autofill.SaveEventLogger.SAVE_UI_SHOWN_REASON_UNKNOWN;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_RECEIVER_EXTRAS;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE;
@@ -457,6 +472,14 @@
@GuardedBy("mLock")
private FillResponseEventLogger mFillResponseEventLogger;
+ @NonNull
+ @GuardedBy("mLock")
+ private SaveEventLogger mSaveEventLogger;
+
+ @NonNull
+ @GuardedBy("mLock")
+ private SessionCommittedEventLogger mSessionCommittedEventLogger;
+
/**
* Fill dialog request would likely be sent slightly later.
*/
@@ -1327,6 +1350,8 @@
mPresentationStatsEventLogger = PresentationStatsEventLogger.forSessionId(sessionId);
mFillRequestEventLogger = FillRequestEventLogger.forSessionId(sessionId);
mFillResponseEventLogger = FillResponseEventLogger.forSessionId(sessionId);
+ mSessionCommittedEventLogger = SessionCommittedEventLogger.forSessionId(sessionId);
+ mSaveEventLogger = SaveEventLogger.forSessionId(sessionId);
synchronized (mLock) {
mSessionFlags = new SessionFlags();
mSessionFlags.mAugmentedAutofillOnly = forAugmentedAutofillOnly;
@@ -2048,6 +2073,12 @@
@Override
public void onSaveRequestSuccess(@NonNull String servicePackageName,
@Nullable IntentSender intentSender) {
+ // Log onSaveRequest result.
+ mSaveEventLogger.maybeSetIsSaved(true);
+ final long saveRequestFinishTimestamp = SystemClock.elapsedRealtime() - mLatencyBaseTime;
+ mSaveEventLogger.maybeSetLatencySaveFinishMillis(saveRequestFinishTimestamp);
+ mSaveEventLogger.logAndEndEvent();
+
synchronized (mLock) {
mSessionFlags.mShowingSaveUi = false;
@@ -2060,6 +2091,8 @@
LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_DATA_SAVE_REQUEST, servicePackageName)
.setType(intentSender == null ? MetricsEvent.TYPE_SUCCESS : MetricsEvent.TYPE_OPEN);
mMetricsLogger.write(log);
+
+
if (intentSender != null) {
if (sDebug) Slog.d(TAG, "Starting intent sender on save()");
startIntentSenderAndFinishSession(intentSender);
@@ -2074,6 +2107,12 @@
public void onSaveRequestFailure(@Nullable CharSequence message,
@NonNull String servicePackageName) {
boolean showMessage = !TextUtils.isEmpty(message);
+
+ // Log onSaveRequest result.
+ final long saveRequestFinishTimestamp = SystemClock.elapsedRealtime() - mLatencyBaseTime;
+ mSaveEventLogger.maybeSetLatencySaveFinishMillis(saveRequestFinishTimestamp);
+ mSaveEventLogger.logAndEndEvent();
+
synchronized (mLock) {
mSessionFlags.mShowingSaveUi = false;
@@ -2099,6 +2138,7 @@
}
mMetricsLogger.write(log);
+
if (showMessage) {
getUiForShowing().showError(message, this);
}
@@ -2188,13 +2228,17 @@
// AutoFillUiCallback
@Override
public void save() {
+ mSaveEventLogger.maybeSetSaveButtonClicked(true);
synchronized (mLock) {
if (mDestroyed) {
Slog.w(TAG, "Call to Session#save() rejected - session: "
+ id + " destroyed");
+ mSaveEventLogger.logAndEndEvent();
return;
}
}
+ final long saveRequestStartTimestamp = SystemClock.elapsedRealtime() - mLatencyBaseTime;
+ mSaveEventLogger.maybeSetLatencySaveRequestMillis(saveRequestStartTimestamp);
mHandler.sendMessage(obtainMessage(
AutofillManagerServiceImpl::handleSessionSave,
mService, this));
@@ -2203,12 +2247,14 @@
// AutoFillUiCallback
@Override
public void cancelSave() {
+ mSaveEventLogger.maybeSetDialogDismissed(true);
synchronized (mLock) {
mSessionFlags.mShowingSaveUi = false;
if (mDestroyed) {
Slog.w(TAG, "Call to Session#cancelSave() rejected - session: "
+ id + " destroyed");
+ mSaveEventLogger.logAndEndEvent();
return;
}
}
@@ -3031,6 +3077,8 @@
if (mDestroyed) {
Slog.w(TAG, "Call to Session#showSaveLocked() rejected - session: "
+ id + " destroyed");
+ mSaveEventLogger.maybeSetSaveUiNotShownReason(NO_SAVE_REASON_SESSION_DESTROYED);
+ mSaveEventLogger.logAndEndEvent();
return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ false,
Event.NO_SAVE_UI_REASON_NONE);
}
@@ -3050,6 +3098,8 @@
*/
if (saveInfo == null) {
if (sVerbose) Slog.v(TAG, "showSaveLocked(" + this.id + "): no saveInfo from service");
+ mSaveEventLogger.maybeSetSaveUiNotShownReason(NO_SAVE_REASON_NO_SAVE_INFO);
+ mSaveEventLogger.logAndEndEvent();
return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ true,
Event.NO_SAVE_UI_REASON_NO_SAVE_INFO);
}
@@ -3057,6 +3107,8 @@
if ((saveInfo.getFlags() & SaveInfo.FLAG_DELAY_SAVE) != 0) {
// TODO(b/113281366): log metrics
if (sDebug) Slog.v(TAG, "showSaveLocked(" + this.id + "): service asked to delay save");
+ mSaveEventLogger.maybeSetSaveUiNotShownReason(NO_SAVE_REASON_WITH_DELAY_SAVE_FLAG);
+ mSaveEventLogger.logAndEndEvent();
return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ false,
Event.NO_SAVE_UI_REASON_WITH_DELAY_SAVE_FLAG);
}
@@ -3130,6 +3182,8 @@
+ "didn't change: " + value);
}
changed = false;
+ } else {
+ mSaveEventLogger.maybeSetIsNewField(true);
}
} else {
isUpdate = true;
@@ -3153,6 +3207,9 @@
int saveDialogNotShowReason;
if (!allRequiredAreNotEmpty) {
saveDialogNotShowReason = Event.NO_SAVE_UI_REASON_HAS_EMPTY_REQUIRED;
+
+ mSaveEventLogger.maybeSetSaveUiNotShownReason(NO_SAVE_REASON_HAS_EMPTY_REQUIRED);
+ mSaveEventLogger.logAndEndEvent();
} else {
// Must look up all optional ids in 2 scenarios:
// - if no required id changed but an optional id did, it should trigger save / update
@@ -3188,6 +3245,8 @@
}
if (filledValue != null) {
isUpdate = true;
+ } else {
+ mSaveEventLogger.maybeSetIsNewField(true);
}
atLeastOneChanged = true;
}
@@ -3206,6 +3265,8 @@
}
if (!atLeastOneChanged) {
saveDialogNotShowReason = Event.NO_SAVE_UI_REASON_NO_VALUE_CHANGED;
+ mSaveEventLogger.maybeSetSaveUiNotShownReason(NO_SAVE_REASON_NO_VALUE_CHANGED);
+ mSaveEventLogger.logAndEndEvent();
} else {
if (sDebug) {
Slog.d(TAG, "at least one field changed, validate fields for save UI");
@@ -3224,6 +3285,9 @@
Slog.e(TAG, "Not showing save UI because validation failed:", e);
log.setType(MetricsEvent.TYPE_FAILURE);
mMetricsLogger.write(log);
+ mSaveEventLogger.maybeSetSaveUiNotShownReason(
+ NO_SAVE_REASON_FIELD_VALIDATION_FAILED);
+ mSaveEventLogger.logAndEndEvent();
return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ true,
Event.NO_SAVE_UI_REASON_FIELD_VALIDATION_FAILED);
}
@@ -3231,6 +3295,9 @@
mMetricsLogger.write(log);
if (!isValid) {
Slog.i(TAG, "not showing save UI because fields failed validation");
+ mSaveEventLogger.maybeSetSaveUiNotShownReason(
+ NO_SAVE_REASON_FIELD_VALIDATION_FAILED);
+ mSaveEventLogger.logAndEndEvent();
return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ true,
Event.NO_SAVE_UI_REASON_FIELD_VALIDATION_FAILED);
}
@@ -3271,6 +3338,8 @@
Slog.d(TAG, "ignoring Save UI because all fields match contents of "
+ "dataset #" + i + ": " + dataset);
}
+ mSaveEventLogger.maybeSetSaveUiNotShownReason(NO_SAVE_REASON_DATASET_MATCH);
+ mSaveEventLogger.logAndEndEvent();
return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ true,
Event.NO_SAVE_UI_REASON_DATASET_MATCH);
}
@@ -3292,14 +3361,18 @@
}
if (serviceLabel == null || serviceIcon == null) {
wtf(null, "showSaveLocked(): no service label or icon");
+ mSaveEventLogger.maybeSetSaveUiNotShownReason(NO_SAVE_REASON_NONE);
+ mSaveEventLogger.logAndEndEvent();
return new SaveResult(/* logSaveShown= */ false, /* removeSession= */ true,
Event.NO_SAVE_UI_REASON_NONE);
}
-
+ final long saveUiDisplayStartTimestamp = SystemClock.elapsedRealtime();
getUiForShowing().showSaveUi(serviceLabel, serviceIcon,
mService.getServicePackageName(), saveInfo, this,
mComponentName, this, mPendingSaveUi, isUpdate, mCompatMode,
response.getShowSaveDialogIcon());
+ mSaveEventLogger.maybeSetLatencySaveUiDisplayMillis(
+ SystemClock.elapsedRealtime()- saveUiDisplayStartTimestamp);
if (client != null) {
try {
client.setSaveUiState(id, true);
@@ -3471,11 +3544,15 @@
if (mDestroyed) {
Slog.w(TAG, "Call to Session#callSaveLocked() rejected - session: "
+ id + " destroyed");
+ mSaveEventLogger.maybeSetIsSaved(false);
+ mSaveEventLogger.logAndEndEvent();
return;
}
if (mRemoteFillService == null) {
wtf(null, "callSaveLocked() called without a remote service. "
+ "mForAugmentedAutofillOnly: %s", mSessionFlags.mAugmentedAutofillOnly);
+ mSaveEventLogger.maybeSetIsSaved(false);
+ mSaveEventLogger.logAndEndEvent();
return;
}
@@ -3483,6 +3560,8 @@
if (mContexts == null) {
Slog.w(TAG, "callSaveLocked(): no contexts");
+ mSaveEventLogger.maybeSetIsSaved(false);
+ mSaveEventLogger.logAndEndEvent();
return;
}
@@ -3899,6 +3978,8 @@
mPresentationStatsEventLogger.maybeSetRequestId(response.getRequestId());
mPresentationStatsEventLogger.maybeSetAvailableCount(
response.getDatasets(), mCurrentViewId);
+ mFillResponseEventLogger.maybeSetAvailableCount(
+ response.getDatasets(), mCurrentViewId);
}
if (isSameViewEntered) {
@@ -4069,6 +4150,11 @@
if (mDestroyed) {
Slog.w(TAG, "Call to Session#onFillReady() rejected - session: "
+ id + " destroyed");
+ mSaveEventLogger.maybeSetSaveUiNotShownReason(NO_SAVE_REASON_SESSION_DESTROYED);
+ mSaveEventLogger.logAndEndEvent();
+ mPresentationStatsEventLogger.maybeSetNoPresentationEventReason(
+ NOT_SHOWN_REASON_SESSION_COMMITTED_PREMATURELY);
+ mPresentationStatsEventLogger.logAndEndEvent();
return;
}
}
@@ -4100,7 +4186,7 @@
synchronized (mLock) {
// Time passed since Session was created
- long suggestionSentRelativeTimestamp =
+ final long suggestionSentRelativeTimestamp =
SystemClock.elapsedRealtime() - mLatencyBaseTime;
mPresentationStatsEventLogger.maybeSetSuggestionSentTimestampMs(
(int) (suggestionSentRelativeTimestamp));
@@ -4468,10 +4554,19 @@
saveTriggerId = saveInfo.getTriggerId();
if (saveTriggerId != null) {
writeLog(MetricsEvent.AUTOFILL_EXPLICIT_SAVE_TRIGGER_DEFINITION);
+ mSaveEventLogger.maybeSetSaveUiShownReason(SAVE_UI_SHOWN_REASON_TRIGGER_ID_SET);
}
flags = saveInfo.getFlags();
mSaveOnAllViewsInvisible = (flags & SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE) != 0;
+ mFillResponseEventLogger.maybeSetSaveUiTriggerIds(HAVE_SAVE_TRIGGER_ID);
+
+ // Start to log Save event.
+ mSaveEventLogger.maybeSetRequestId(response.getRequestId());
+ mSaveEventLogger.maybeSetAppPackageUid(uid);
+ mSaveEventLogger.maybeSetSaveUiTriggerIds(HAVE_SAVE_TRIGGER_ID);
+ mSaveEventLogger.maybeSetFlag(flags);
+
// We only need to track views if we want to save once they become invisible.
if (mSaveOnAllViewsInvisible) {
if (trackedViews == null) {
@@ -4479,18 +4574,28 @@
}
if (saveInfo.getRequiredIds() != null) {
Collections.addAll(trackedViews, saveInfo.getRequiredIds());
+ mSaveEventLogger.maybeSetSaveUiShownReason(
+ SAVE_UI_SHOWN_REASON_REQUIRED_ID_CHANGE);
}
if (saveInfo.getOptionalIds() != null) {
Collections.addAll(trackedViews, saveInfo.getOptionalIds());
+ mSaveEventLogger.maybeSetSaveUiShownReason(
+ SAVE_UI_SHOWN_REASON_OPTIONAL_ID_CHANGE);
}
}
if ((flags & SaveInfo.FLAG_DONT_SAVE_ON_FINISH) != 0) {
+ mSaveEventLogger.maybeSetSaveUiShownReason(
+ SAVE_UI_SHOWN_REASON_UNKNOWN);
+ mSaveEventLogger.maybeSetSaveUiNotShownReason(
+ NO_SAVE_REASON_WITH_DONT_SAVE_ON_FINISH_FLAG);
saveOnFinish = false;
}
} else {
flags = 0;
+ mSaveEventLogger.maybeSetSaveUiNotShownReason(
+ NO_SAVE_REASON_NO_SAVE_INFO);
saveTriggerId = null;
}
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index 1363ef3..ae88f24 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -126,7 +126,7 @@
private final VirtualDeviceManagerService mService;
private final PendingTrampolineCallback mPendingTrampolineCallback;
private final int mOwnerUid;
- private final int mDeviceId;
+ private int mDeviceId;
// Thou shall not hold the mVirtualDeviceLock over the mInputController calls.
// Holding the lock can lead to lock inversion with GlobalWindowManagerLock.
// 1. After display is created the window manager calls into VDM during construction
@@ -348,6 +348,7 @@
@Override // Binder call
public void launchPendingIntent(int displayId, PendingIntent pendingIntent,
ResultReceiver resultReceiver) {
+ Objects.requireNonNull(pendingIntent);
synchronized (mVirtualDeviceLock) {
if (!mVirtualDisplays.contains(displayId)) {
throw new SecurityException("Display ID " + displayId
@@ -404,6 +405,7 @@
super.close_enforcePermission();
// Remove about-to-be-closed virtual device from the service before butchering it.
mService.removeVirtualDevice(mDeviceId);
+ mDeviceId = Context.DEVICE_ID_INVALID;
VirtualDisplayWrapper[] virtualDisplaysToBeReleased;
synchronized (mVirtualDeviceLock) {
@@ -497,6 +499,7 @@
@EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
public void createVirtualDpad(VirtualDpadConfig config, @NonNull IBinder deviceToken) {
super.createVirtualDpad_enforcePermission();
+ Objects.requireNonNull(config);
synchronized (mVirtualDeviceLock) {
if (!mVirtualDisplays.contains(config.getAssociatedDisplayId())) {
throw new SecurityException(
@@ -517,6 +520,7 @@
@EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
public void createVirtualKeyboard(VirtualKeyboardConfig config, @NonNull IBinder deviceToken) {
super.createVirtualKeyboard_enforcePermission();
+ Objects.requireNonNull(config);
synchronized (mVirtualDeviceLock) {
if (!mVirtualDisplays.contains(config.getAssociatedDisplayId())) {
throw new SecurityException(
@@ -539,6 +543,7 @@
@EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
public void createVirtualMouse(VirtualMouseConfig config, @NonNull IBinder deviceToken) {
super.createVirtualMouse_enforcePermission();
+ Objects.requireNonNull(config);
synchronized (mVirtualDeviceLock) {
if (!mVirtualDisplays.contains(config.getAssociatedDisplayId())) {
throw new SecurityException(
@@ -560,6 +565,7 @@
public void createVirtualTouchscreen(VirtualTouchscreenConfig config,
@NonNull IBinder deviceToken) {
super.createVirtualTouchscreen_enforcePermission();
+ Objects.requireNonNull(config);
synchronized (mVirtualDeviceLock) {
if (!mVirtualDisplays.contains(config.getAssociatedDisplayId())) {
throw new SecurityException(
@@ -590,6 +596,7 @@
public void createVirtualNavigationTouchpad(VirtualNavigationTouchpadConfig config,
@NonNull IBinder deviceToken) {
super.createVirtualNavigationTouchpad_enforcePermission();
+ Objects.requireNonNull(config);
synchronized (mVirtualDeviceLock) {
if (!mVirtualDisplays.contains(config.getAssociatedDisplayId())) {
throw new SecurityException(
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
index 3b1983f..291c0587 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -66,7 +66,10 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
@@ -86,6 +89,14 @@
private static AtomicInteger sNextUniqueIndex = new AtomicInteger(
Context.DEVICE_ID_DEFAULT + 1);
+ private final CompanionDeviceManager.OnAssociationsChangedListener mCdmAssociationListener =
+ new CompanionDeviceManager.OnAssociationsChangedListener() {
+ @Override
+ public void onAssociationsChanged(@NonNull List<AssociationInfo> associations) {
+ syncVirtualDevicesToCdmAssociations(associations);
+ }
+ };
+
/**
* Mapping from device IDs to virtual devices.
*/
@@ -204,11 +215,56 @@
final long identity = Binder.clearCallingIdentity();
try {
getContext().sendBroadcastAsUser(i, UserHandle.ALL);
+
+ synchronized (mVirtualDeviceManagerLock) {
+ if (mVirtualDevices.size() == 0) {
+ unregisterCdmAssociationListener();
+ }
+ }
} finally {
Binder.restoreCallingIdentity(identity);
}
}
+ private void syncVirtualDevicesToCdmAssociations(List<AssociationInfo> associations) {
+ Set<VirtualDeviceImpl> virtualDevicesToRemove = new HashSet<>();
+ synchronized (mVirtualDeviceManagerLock) {
+ if (mVirtualDevices.size() == 0) {
+ return;
+ }
+
+ Set<Integer> activeAssociationIds = new HashSet<>(associations.size());
+ for (AssociationInfo association : associations) {
+ activeAssociationIds.add(association.getId());
+ }
+
+ for (int i = 0; i < mVirtualDevices.size(); i++) {
+ VirtualDeviceImpl virtualDevice = mVirtualDevices.valueAt(i);
+ if (!activeAssociationIds.contains(virtualDevice.getAssociationId())) {
+ virtualDevicesToRemove.add(virtualDevice);
+ }
+ }
+ }
+
+ for (VirtualDeviceImpl virtualDevice : virtualDevicesToRemove) {
+ virtualDevice.close();
+ }
+
+ }
+
+ private void registerCdmAssociationListener() {
+ final CompanionDeviceManager cdm = getContext().getSystemService(
+ CompanionDeviceManager.class);
+ cdm.addOnAssociationsChangedListener(getContext().getMainExecutor(),
+ mCdmAssociationListener);
+ }
+
+ private void unregisterCdmAssociationListener() {
+ final CompanionDeviceManager cdm = getContext().getSystemService(
+ CompanionDeviceManager.class);
+ cdm.removeOnAssociationsChangedListener(mCdmAssociationListener);
+ }
+
class VirtualDeviceManagerImpl extends IVirtualDeviceManager.Stub {
private final VirtualDeviceImpl.PendingTrampolineCallback mPendingTrampolineCallback =
@@ -254,7 +310,20 @@
if (associationInfo == null) {
throw new IllegalArgumentException("No association with ID " + associationId);
}
+ Objects.requireNonNull(params);
+ Objects.requireNonNull(activityListener);
+ Objects.requireNonNull(soundEffectListener);
+
synchronized (mVirtualDeviceManagerLock) {
+ if (mVirtualDevices.size() == 0) {
+ final long callindId = Binder.clearCallingIdentity();
+ try {
+ registerCdmAssociationListener();
+ } finally {
+ Binder.restoreCallingIdentity(callindId);
+ }
+ }
+
final UserHandle userHandle = getCallingUserHandle();
final CameraAccessController cameraAccessController =
getCameraAccessController(userHandle);
@@ -275,6 +344,7 @@
public int createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig,
IVirtualDisplayCallback callback, IVirtualDevice virtualDevice, String packageName)
throws RemoteException {
+ Objects.requireNonNull(virtualDisplayConfig);
final int callingUid = getCallingUid();
if (!PermissionUtils.validateCallingPackageName(getContext(), packageName)) {
throw new SecurityException(
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index af5609a..299f865 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -75,10 +75,11 @@
private static final int MSG_UPDATE_AMBIENT_LUX = 1;
private static final int MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE = 2;
- private static final int MSG_INVALIDATE_SHORT_TERM_MODEL = 3;
+ private static final int MSG_INVALIDATE_CURRENT_SHORT_TERM_MODEL = 3;
private static final int MSG_UPDATE_FOREGROUND_APP = 4;
private static final int MSG_UPDATE_FOREGROUND_APP_SYNC = 5;
private static final int MSG_RUN_UPDATE = 6;
+ private static final int MSG_INVALIDATE_PAUSED_SHORT_TERM_MODEL = 7;
// Callbacks for requesting updates to the display's power state
private final Callbacks mCallbacks;
@@ -216,12 +217,11 @@
private float mBrightnessAdjustmentSampleOldLux;
private float mBrightnessAdjustmentSampleOldBrightness;
- // When the short term model is invalidated, we don't necessarily reset it (i.e. clear the
- // user's adjustment) immediately, but wait for a drastic enough change in the ambient light.
- // The anchor determines what were the light levels when the user has set their preference, and
- // we use a relative threshold to determine when to revert to the OEM curve.
- private boolean mShortTermModelValid;
- private float mShortTermModelAnchor;
+ // The short term models, current and previous. Eg, we might use the "paused" one to save out
+ // the interactive short term model when switching to idle screen brightness mode, and
+ // vice-versa.
+ private final ShortTermModel mShortTermModel;
+ private final ShortTermModel mPausedShortTermModel;
// Controls High Brightness Mode.
private HighBrightnessModeController mHbmController;
@@ -309,8 +309,8 @@
mAmbientBrightnessThresholdsIdle = ambientBrightnessThresholdsIdle;
mScreenBrightnessThresholds = screenBrightnessThresholds;
mScreenBrightnessThresholdsIdle = screenBrightnessThresholdsIdle;
- mShortTermModelValid = true;
- mShortTermModelAnchor = -1;
+ mShortTermModel = new ShortTermModel();
+ mPausedShortTermModel = new ShortTermModel();
mHandler = new AutomaticBrightnessHandler(looper);
mAmbientLightRingBuffer =
new AmbientLightRingBuffer(mNormalLightSensorRate, mAmbientLightHorizonLong, mClock);
@@ -492,10 +492,10 @@
Slog.d(TAG, "Display policy transitioning from " + oldPolicy + " to " + policy);
}
if (!isInteractivePolicy(policy) && isInteractivePolicy(oldPolicy) && !isInIdleMode()) {
- mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_SHORT_TERM_MODEL,
+ mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_CURRENT_SHORT_TERM_MODEL,
mCurrentBrightnessMapper.getShortTermModelTimeout());
} else if (isInteractivePolicy(policy) && !isInteractivePolicy(oldPolicy)) {
- mHandler.removeMessages(MSG_INVALIDATE_SHORT_TERM_MODEL);
+ mHandler.removeMessages(MSG_INVALIDATE_CURRENT_SHORT_TERM_MODEL);
}
return true;
}
@@ -516,25 +516,13 @@
private boolean setScreenBrightnessByUser(float lux, float brightness) {
mCurrentBrightnessMapper.addUserDataPoint(lux, brightness);
- mShortTermModelValid = true;
- mShortTermModelAnchor = lux;
- if (mLoggingEnabled) {
- Slog.d(TAG, "ShortTermModel: anchor=" + mShortTermModelAnchor);
- }
+ mShortTermModel.setUserBrightness(lux, brightness);
return true;
}
public void resetShortTermModel() {
mCurrentBrightnessMapper.clearUserDataPoints();
- mShortTermModelValid = true;
- mShortTermModelAnchor = -1;
- }
-
- private void invalidateShortTermModel() {
- if (mLoggingEnabled) {
- Slog.d(TAG, "ShortTermModel: invalidate user data");
- }
- mShortTermModelValid = false;
+ mShortTermModel.reset();
}
public boolean setBrightnessConfiguration(BrightnessConfiguration configuration,
@@ -595,8 +583,12 @@
pw.println(" mShortTermModelTimeout(idle)="
+ mIdleModeBrightnessMapper.getShortTermModelTimeout());
}
- pw.println(" mShortTermModelAnchor=" + mShortTermModelAnchor);
- pw.println(" mShortTermModelValid=" + mShortTermModelValid);
+ pw.println(" mShortTermModel=");
+ mShortTermModel.dump(pw);
+ pw.println(" mPausedShortTermModel=");
+ mPausedShortTermModel.dump(pw);
+
+ pw.println();
pw.println(" mBrightnessAdjustmentSamplePending=" + mBrightnessAdjustmentSamplePending);
pw.println(" mBrightnessAdjustmentSampleOldLux=" + mBrightnessAdjustmentSampleOldLux);
pw.println(" mBrightnessAdjustmentSampleOldBrightness="
@@ -740,15 +732,9 @@
}
mHbmController.onAmbientLuxChange(mAmbientLux);
+
// If the short term model was invalidated and the change is drastic enough, reset it.
- if (!mShortTermModelValid && mShortTermModelAnchor != -1) {
- if (mCurrentBrightnessMapper.shouldResetShortTermModel(
- mAmbientLux, mShortTermModelAnchor)) {
- resetShortTermModel();
- } else {
- mShortTermModelValid = true;
- }
- }
+ mShortTermModel.maybeReset(mAmbientLux);
}
private float calculateAmbientLux(long now, long horizon) {
@@ -1118,8 +1104,29 @@
return;
}
Slog.i(TAG, "Switching to Idle Screen Brightness Mode");
+ // Stash short term model
+ ShortTermModel tempShortTermModel = new ShortTermModel();
+ tempShortTermModel.set(mCurrentBrightnessMapper.getUserLux(),
+ mCurrentBrightnessMapper.getUserBrightness(), /* valid= */ true);
+
+ // Send delayed timeout
+ mHandler.sendEmptyMessageAtTime(MSG_INVALIDATE_PAUSED_SHORT_TERM_MODEL,
+ mClock.uptimeMillis()
+ + mCurrentBrightnessMapper.getShortTermModelTimeout());
+
+ Slog.i(TAG, "mPreviousShortTermModel" + mPausedShortTermModel);
+ // new brightness mapper
mCurrentBrightnessMapper = mIdleModeBrightnessMapper;
- resetShortTermModel();
+
+ // if previous stm has been invalidated, and lux has drastically changed, just use
+ // the new, reset stm.
+ // if previous stm is still valid then revalidate it
+ if (mPausedShortTermModel != null && !mPausedShortTermModel.maybeReset(mAmbientLux)) {
+ setScreenBrightnessByUser(mPausedShortTermModel.mAnchor,
+ mPausedShortTermModel.mBrightness);
+ }
+ mPausedShortTermModel.copyFrom(tempShortTermModel);
+
update();
}
@@ -1128,8 +1135,28 @@
return;
}
Slog.i(TAG, "Switching to Interactive Screen Brightness Mode");
+ ShortTermModel tempShortTermModel = new ShortTermModel();
+ tempShortTermModel.set(mCurrentBrightnessMapper.getUserLux(),
+ mCurrentBrightnessMapper.getUserBrightness(), /* valid= */ true);
+ mHandler.removeMessages(MSG_INVALIDATE_PAUSED_SHORT_TERM_MODEL);
+ // Send delayed timeout
+ mHandler.sendEmptyMessageAtTime(MSG_INVALIDATE_PAUSED_SHORT_TERM_MODEL,
+ mClock.uptimeMillis()
+ + mCurrentBrightnessMapper.getShortTermModelTimeout());
+ Slog.i(TAG, "mPreviousShortTermModel" + mPausedShortTermModel.toString());
+
+ // restore interactive mapper.
mCurrentBrightnessMapper = mInteractiveModeBrightnessMapper;
- resetShortTermModel();
+
+ // if previous stm has been invalidated, and lux has drastically changed, just use
+ // the new, reset stm.
+ // if previous stm is still valid then revalidate it
+ if (!mPausedShortTermModel.maybeReset(mAmbientLux)) {
+ setScreenBrightnessByUser(mPausedShortTermModel.mAnchor,
+ mPausedShortTermModel.mBrightness);
+ }
+ mPausedShortTermModel.copyFrom(tempShortTermModel);
+
update();
}
@@ -1164,6 +1191,77 @@
}
}
+ private class ShortTermModel {
+ // When the short term model is invalidated, we don't necessarily reset it (i.e. clear the
+ // user's adjustment) immediately, but wait for a drastic enough change in the ambient
+ // light.
+ // The anchor determines what were the light levels when the user has set their preference,
+ // and we use a relative threshold to determine when to revert to the OEM curve.
+ private float mAnchor = -1f;
+ private float mBrightness;
+ private boolean mIsValid = true;
+
+ private void reset() {
+ mAnchor = -1f;
+ mBrightness = -1f;
+ mIsValid = true;
+ }
+
+ private void invalidate() {
+ mIsValid = false;
+ if (mLoggingEnabled) {
+ Slog.d(TAG, "ShortTermModel: invalidate user data");
+ }
+ }
+
+ private void setUserBrightness(float lux, float brightness) {
+ mAnchor = lux;
+ mBrightness = brightness;
+ mIsValid = true;
+ if (mLoggingEnabled) {
+ Slog.d(TAG, "ShortTermModel: anchor=" + mAnchor);
+ }
+ }
+
+ private boolean maybeReset(float currentLux) {
+ // If the short term model was invalidated and the change is drastic enough, reset it.
+ // Otherwise, we revalidate it.
+ if (!mIsValid && mAnchor != -1) {
+ if (mCurrentBrightnessMapper != null
+ && mCurrentBrightnessMapper.shouldResetShortTermModel(
+ currentLux, mAnchor)) {
+ resetShortTermModel();
+ } else {
+ mIsValid = true;
+ }
+ return mIsValid;
+ }
+ return false;
+ }
+
+ private void set(float anchor, float brightness, boolean valid) {
+ mAnchor = anchor;
+ mBrightness = brightness;
+ mIsValid = valid;
+ }
+ private void copyFrom(ShortTermModel from) {
+ mAnchor = from.mAnchor;
+ mBrightness = from.mBrightness;
+ mIsValid = from.mIsValid;
+ }
+
+ public String toString() {
+ return " mAnchor: " + mAnchor
+ + "\n mBrightness: " + mBrightness
+ + "\n mIsValid: " + mIsValid;
+ }
+
+ void dump(PrintWriter pw) {
+ pw.println(this);
+ }
+
+ }
+
private final class AutomaticBrightnessHandler extends Handler {
public AutomaticBrightnessHandler(Looper looper) {
super(looper, null, true /*async*/);
@@ -1184,8 +1282,8 @@
collectBrightnessAdjustmentSample();
break;
- case MSG_INVALIDATE_SHORT_TERM_MODEL:
- invalidateShortTermModel();
+ case MSG_INVALIDATE_CURRENT_SHORT_TERM_MODEL:
+ mShortTermModel.invalidate();
break;
case MSG_UPDATE_FOREGROUND_APP:
@@ -1195,6 +1293,10 @@
case MSG_UPDATE_FOREGROUND_APP_SYNC:
updateForegroundAppSync();
break;
+
+ case MSG_INVALIDATE_PAUSED_SHORT_TERM_MODEL:
+ mPausedShortTermModel.invalidate();
+ break;
}
}
}
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index d047183..3456e3e 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -363,13 +363,17 @@
public abstract void recalculateSplines(boolean applyAdjustment, float[] adjustment);
/**
- * Returns the timeout for the short term model
+ * Returns the timeout, in milliseconds for the short term model
*
* Timeout after which we remove the effects any user interactions might've had on the
* brightness mapping. This timeout doesn't start until we transition to a non-interactive
* display policy so that we don't reset while users are using their devices, but also so that
* we don't erroneously keep the short-term model if the device is dozing but the
* display is fully on.
+ *
+ * This timeout is also used when the device switches from interactive screen brightness mode
+ * to idle screen brightness mode, to preserve the user's preference when they resume usage of
+ * the device, within the specified timeframe.
*/
public abstract long getShortTermModelTimeout();
diff --git a/services/core/java/com/android/server/display/BrightnessThrottler.java b/services/core/java/com/android/server/display/BrightnessThrottler.java
index eccee52..067a2d6 100644
--- a/services/core/java/com/android/server/display/BrightnessThrottler.java
+++ b/services/core/java/com/android/server/display/BrightnessThrottler.java
@@ -16,7 +16,10 @@
package com.android.server.display;
+import static com.android.server.display.DisplayDeviceConfig.DEFAULT_ID;
+
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.hardware.display.BrightnessInfo;
import android.hardware.display.DisplayManager;
@@ -63,8 +66,16 @@
private final DeviceConfigInterface mDeviceConfig;
private int mThrottlingStatus;
+
+ // Maps the throttling ID to the data. Sourced from DisplayDeviceConfig.
+ @NonNull
+ private HashMap<String, BrightnessThrottlingData> mDdcThrottlingDataMap;
+
+ // Current throttling data being used.
+ // Null if we do not support throttling.
+ @Nullable
private BrightnessThrottlingData mThrottlingData;
- private BrightnessThrottlingData mDdcThrottlingData;
+
private float mBrightnessCap = PowerManager.BRIGHTNESS_MAX;
private @BrightnessInfo.BrightnessMaxReason int mBrightnessMaxReason =
BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE;
@@ -73,35 +84,45 @@
// The most recent string that has been set from DeviceConfig
private String mBrightnessThrottlingDataString;
+ // The brightness throttling configuration that should be used.
+ private String mBrightnessThrottlingDataId;
+
// This is a collection of brightness throttling data that has been written as overrides from
// the DeviceConfig. This will always take priority over the display device config data.
- private HashMap<String, BrightnessThrottlingData> mBrightnessThrottlingDataOverride =
- new HashMap<>(1);
+ // We need to store the data for every display device, so we do not need to update this each
+ // time the underlying display device changes.
+ // This map is indexed by uniqueDisplayId, to provide maps for throttlingId -> throttlingData.
+ // HashMap< uniqueDisplayId, HashMap< throttlingDataId, BrightnessThrottlingData >>
+ private final HashMap<String, HashMap<String, BrightnessThrottlingData>>
+ mBrightnessThrottlingDataOverride = new HashMap<>(1);
- BrightnessThrottler(Handler handler, BrightnessThrottlingData throttlingData,
- Runnable throttlingChangeCallback, String uniqueDisplayId) {
- this(new Injector(), handler, handler, throttlingData, throttlingChangeCallback,
- uniqueDisplayId);
+ BrightnessThrottler(Handler handler, Runnable throttlingChangeCallback, String uniqueDisplayId,
+ String throttlingDataId,
+ @NonNull HashMap<String, BrightnessThrottlingData> brightnessThrottlingDataMap) {
+ this(new Injector(), handler, handler, throttlingChangeCallback,
+ uniqueDisplayId, throttlingDataId, brightnessThrottlingDataMap);
}
@VisibleForTesting
BrightnessThrottler(Injector injector, Handler handler, Handler deviceConfigHandler,
- BrightnessThrottlingData throttlingData, Runnable throttlingChangeCallback,
- String uniqueDisplayId) {
+ Runnable throttlingChangeCallback, String uniqueDisplayId, String throttlingDataId,
+ @NonNull HashMap<String, BrightnessThrottlingData> brightnessThrottlingDataMap) {
mInjector = injector;
mHandler = handler;
mDeviceConfigHandler = deviceConfigHandler;
- mThrottlingData = throttlingData;
- mDdcThrottlingData = throttlingData;
+ mDdcThrottlingDataMap = brightnessThrottlingDataMap;
mThrottlingChangeCallback = throttlingChangeCallback;
mSkinThermalStatusObserver = new SkinThermalStatusObserver(mInjector, mHandler);
mUniqueDisplayId = uniqueDisplayId;
mDeviceConfig = injector.getDeviceConfig();
mDeviceConfigListener = new DeviceConfigListener();
-
- resetThrottlingData(mThrottlingData, mUniqueDisplayId);
+ mBrightnessThrottlingDataId = throttlingDataId;
+ mDdcThrottlingDataMap = brightnessThrottlingDataMap;
+ loadBrightnessThrottlingDataFromDeviceConfig();
+ loadBrightnessThrottlingDataFromDisplayDeviceConfig(mDdcThrottlingDataMap,
+ mBrightnessThrottlingDataId, mUniqueDisplayId);
}
boolean deviceSupportsThrottling() {
@@ -133,23 +154,14 @@
mThrottlingStatus = THROTTLING_INVALID;
}
- private void resetThrottlingData() {
- resetThrottlingData(mDdcThrottlingData, mUniqueDisplayId);
- }
-
- void resetThrottlingData(BrightnessThrottlingData throttlingData, String displayId) {
- stop();
-
- mUniqueDisplayId = displayId;
- mDdcThrottlingData = throttlingData;
- mDeviceConfigListener.startListening();
- reloadBrightnessThrottlingDataOverride();
- mThrottlingData = mBrightnessThrottlingDataOverride.getOrDefault(mUniqueDisplayId,
- throttlingData);
-
- if (deviceSupportsThrottling()) {
- mSkinThermalStatusObserver.startObserving();
- }
+ void loadBrightnessThrottlingDataFromDisplayDeviceConfig(
+ HashMap<String, BrightnessThrottlingData> ddcThrottlingDataMap,
+ String brightnessThrottlingDataId,
+ String uniqueDisplayId) {
+ mDdcThrottlingDataMap = ddcThrottlingDataMap;
+ mBrightnessThrottlingDataId = brightnessThrottlingDataId;
+ mUniqueDisplayId = uniqueDisplayId;
+ resetThrottlingData();
}
private float verifyAndConstrainBrightnessCap(float brightness) {
@@ -183,7 +195,7 @@
float brightnessCap = PowerManager.BRIGHTNESS_MAX;
int brightnessMaxReason = BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE;
- if (mThrottlingStatus != THROTTLING_INVALID) {
+ if (mThrottlingStatus != THROTTLING_INVALID && mThrottlingData != null) {
// Throttling levels are sorted by increasing severity
for (ThrottlingLevel level : mThrottlingData.throttlingLevels) {
if (level.thermalStatus <= mThrottlingStatus) {
@@ -218,13 +230,14 @@
private void dumpLocal(PrintWriter pw) {
pw.println("BrightnessThrottler:");
+ pw.println(" mBrightnessThrottlingDataId=" + mBrightnessThrottlingDataId);
pw.println(" mThrottlingData=" + mThrottlingData);
- pw.println(" mDdcThrottlingData=" + mDdcThrottlingData);
pw.println(" mUniqueDisplayId=" + mUniqueDisplayId);
pw.println(" mThrottlingStatus=" + mThrottlingStatus);
pw.println(" mBrightnessCap=" + mBrightnessCap);
pw.println(" mBrightnessMaxReason=" +
BrightnessInfo.briMaxReasonToString(mBrightnessMaxReason));
+ pw.println(" mDdcThrottlingDataMap=" + mDdcThrottlingDataMap);
pw.println(" mBrightnessThrottlingDataOverride=" + mBrightnessThrottlingDataOverride);
pw.println(" mBrightnessThrottlingDataString=" + mBrightnessThrottlingDataString);
@@ -237,8 +250,18 @@
/* defaultValue= */ null);
}
- private boolean parseAndSaveData(@NonNull String strArray,
- @NonNull HashMap<String, BrightnessThrottlingData> tempBrightnessThrottlingData) {
+ // The brightness throttling data id may or may not be specified in the string that is passed
+ // in, if there is none specified, we assume it is for the default case. Each string passed in
+ // here must be for one display and one throttling id.
+ // 123,1,critical,0.8
+ // 456,2,moderate,0.9,critical,0.7
+ // 456,2,moderate,0.9,critical,0.7,default
+ // 456,2,moderate,0.9,critical,0.7,id_2
+ // displayId, number, <state, val> * number
+ // displayId, <number, <state, val> * number>, throttlingId
+ private boolean parseAndAddData(@NonNull String strArray,
+ @NonNull HashMap<String, HashMap<String, BrightnessThrottlingData>>
+ displayIdToThrottlingIdToBtd) {
boolean validConfig = true;
String[] items = strArray.split(",");
int i = 0;
@@ -254,29 +277,42 @@
for (int j = 0; j < noOfThrottlingPoints; j++) {
String severity = items[i++];
int status = parseThermalStatus(severity);
-
float brightnessPoint = parseBrightness(items[i++]);
-
throttlingLevels.add(new ThrottlingLevel(status, brightnessPoint));
}
- BrightnessThrottlingData toSave =
+
+ String throttlingDataId = (i < items.length) ? items[i++] : DEFAULT_ID;
+ BrightnessThrottlingData throttlingLevelsData =
DisplayDeviceConfig.BrightnessThrottlingData.create(throttlingLevels);
- tempBrightnessThrottlingData.put(uniqueDisplayId, toSave);
+
+ // Add throttlingLevelsData to inner map where necessary.
+ HashMap<String, BrightnessThrottlingData> throttlingMapForDisplay =
+ displayIdToThrottlingIdToBtd.get(uniqueDisplayId);
+ if (throttlingMapForDisplay == null) {
+ throttlingMapForDisplay = new HashMap<>();
+ throttlingMapForDisplay.put(throttlingDataId, throttlingLevelsData);
+ displayIdToThrottlingIdToBtd.put(uniqueDisplayId, throttlingMapForDisplay);
+ } else if (throttlingMapForDisplay.containsKey(throttlingDataId)) {
+ Slog.e(TAG, "Throttling data for display " + uniqueDisplayId
+ + "contains duplicate throttling ids: '" + throttlingDataId + "'");
+ return false;
+ } else {
+ throttlingMapForDisplay.put(throttlingDataId, throttlingLevelsData);
+ }
} catch (NumberFormatException | IndexOutOfBoundsException
| UnknownThermalStatusException e) {
- validConfig = false;
Slog.e(TAG, "Throttling data is invalid array: '" + strArray + "'", e);
+ validConfig = false;
}
if (i != items.length) {
validConfig = false;
}
-
return validConfig;
}
- public void reloadBrightnessThrottlingDataOverride() {
- HashMap<String, BrightnessThrottlingData> tempBrightnessThrottlingData =
+ private void loadBrightnessThrottlingDataFromDeviceConfig() {
+ HashMap<String, HashMap<String, BrightnessThrottlingData>> tempThrottlingData =
new HashMap<>(1);
mBrightnessThrottlingDataString = getBrightnessThrottlingDataString();
boolean validConfig = true;
@@ -284,15 +320,15 @@
if (mBrightnessThrottlingDataString != null) {
String[] throttlingDataSplits = mBrightnessThrottlingDataString.split(";");
for (String s : throttlingDataSplits) {
- if (!parseAndSaveData(s, tempBrightnessThrottlingData)) {
+ if (!parseAndAddData(s, tempThrottlingData)) {
validConfig = false;
break;
}
}
if (validConfig) {
- mBrightnessThrottlingDataOverride.putAll(tempBrightnessThrottlingData);
- tempBrightnessThrottlingData.clear();
+ mBrightnessThrottlingDataOverride.putAll(tempThrottlingData);
+ tempThrottlingData.clear();
}
} else {
@@ -300,15 +336,50 @@
}
}
+ private void resetThrottlingData() {
+ stop();
+
+ mDeviceConfigListener.startListening();
+
+ // Get throttling data for this id, if it exists
+ mThrottlingData = getConfigFromId(mBrightnessThrottlingDataId);
+
+ // Fallback to default id otherwise.
+ if (!DEFAULT_ID.equals(mBrightnessThrottlingDataId) && mThrottlingData == null) {
+ mThrottlingData = getConfigFromId(DEFAULT_ID);
+ Slog.d(TAG, "Falling back to default throttling Id");
+ }
+
+ if (deviceSupportsThrottling()) {
+ mSkinThermalStatusObserver.startObserving();
+ }
+ }
+
+ private BrightnessThrottlingData getConfigFromId(String id) {
+ BrightnessThrottlingData returnValue;
+
+ // Fallback pattern for fetching correct throttling data for this display and id.
+ // 1) throttling data from device config for this throttling data id
+ returnValue = mBrightnessThrottlingDataOverride.get(mUniqueDisplayId) == null
+ ? null
+ : mBrightnessThrottlingDataOverride.get(mUniqueDisplayId).get(id);
+ // 2) throttling data from ddc for this throttling data id
+ returnValue = returnValue == null
+ ? mDdcThrottlingDataMap.get(id)
+ : returnValue;
+
+ return returnValue;
+ }
+
/**
* Listens to config data change and updates the brightness throttling data using
* DisplayManager#KEY_BRIGHTNESS_THROTTLING_DATA.
* The format should be a string similar to: "local:4619827677550801152,2,moderate,0.5,severe,
* 0.379518072;local:4619827677550801151,1,moderate,0.75"
* In this order:
- * <displayId>,<no of throttling levels>,[<severity as string>,<brightness cap>]
- * Where the latter part is repeated for each throttling level, and the entirety is repeated
- * for each display, separated by a semicolon.
+ * <displayId>,<no of throttling levels>,[<severity as string>,<brightness cap>][,throttlingId]?
+ * Where [<severity as string>,<brightness cap>] is repeated for each throttling level, and the
+ * entirety is repeated for each display & throttling data id, separated by a semicolon.
*/
public class DeviceConfigListener implements DeviceConfig.OnPropertiesChangedListener {
public Executor mExecutor = new HandlerExecutor(mDeviceConfigHandler);
@@ -320,7 +391,7 @@
@Override
public void onPropertiesChanged(DeviceConfig.Properties properties) {
- reloadBrightnessThrottlingDataOverride();
+ loadBrightnessThrottlingDataFromDeviceConfig();
resetThrottlingData();
}
}
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index f4b3f1a..da02115 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -143,17 +143,17 @@
* <brightness>0.01</brightness>
* </brightnessThrottlingPoint>
* </brightnessThrottlingMap>
- * <concurrentDisplaysBrightnessThrottlingMap>
- * <brightnessThrottlingPoint>
- * <thermalStatus>severe</thermalStatus>
- * <brightness>0.07</brightness>
- * </brightnessThrottlingPoint>
- * <brightnessThrottlingPoint>
- * <thermalStatus>critical</thermalStatus>
- * <brightness>0.005</brightness>
- * </brightnessThrottlingPoint>
- * </concurrentDisplaysBrightnessThrottlingMap>
- * <refreshRateThrottlingMap>
+ * <brightnessThrottlingMap id="id_2"> // optional attribute, leave blank for default
+ * <brightnessThrottlingPoint>
+ * <thermalStatus>moderate</thermalStatus>
+ * <brightness>0.2</brightness>
+ * </brightnessThrottlingPoint>
+ * <brightnessThrottlingPoint>
+ * <thermalStatus>severe</thermalStatus>
+ * <brightness>0.1</brightness>
+ * </brightnessThrottlingPoint>
+ * </brightnessThrottlingMap>
+ <refreshRateThrottlingMap>
* <refreshRateThrottlingPoint>
* <thermalStatus>critical</thermalStatus>
* <refreshRateRange>
@@ -687,8 +687,8 @@
private int[] mHighDisplayBrightnessThresholds = DEFAULT_BRIGHTNESS_THRESHOLDS;
private int[] mHighAmbientBrightnessThresholds = DEFAULT_BRIGHTNESS_THRESHOLDS;
- private final Map<String, BrightnessThrottlingData> mBrightnessThrottlingDataMap =
- new HashMap<>();
+ private final HashMap<String, BrightnessThrottlingData>
+ mBrightnessThrottlingDataMapByThrottlingId = new HashMap<>();
private final Map<String, SparseArray<SurfaceControl.RefreshRateRange>>
mRefreshRateThrottlingMap = new HashMap<>();
@@ -1346,11 +1346,11 @@
}
/**
- * @param id The ID of the throttling data
- * @return brightness throttling configuration data for the display.
+ * @return brightness throttling configuration data for this display, for each throttling id.
*/
- public BrightnessThrottlingData getBrightnessThrottlingData(String id) {
- return BrightnessThrottlingData.create(mBrightnessThrottlingDataMap.get(id));
+ public HashMap<String, BrightnessThrottlingData>
+ getBrightnessThrottlingDataMapByThrottlingId() {
+ return mBrightnessThrottlingDataMapByThrottlingId;
}
/**
@@ -1525,7 +1525,8 @@
+ ", isHbmEnabled=" + mIsHighBrightnessModeEnabled
+ ", mHbmData=" + mHbmData
+ ", mSdrToHdrRatioSpline=" + mSdrToHdrRatioSpline
- + ", mBrightnessThrottlingData=" + mBrightnessThrottlingDataMap
+ + ", mBrightnessThrottlingDataMapByThrottlingId="
+ + mBrightnessThrottlingDataMapByThrottlingId
+ "\n"
+ ", mBrightnessRampFastDecrease=" + mBrightnessRampFastDecrease
+ ", mBrightnessRampFastIncrease=" + mBrightnessRampFastIncrease
@@ -1918,11 +1919,11 @@
if (!badConfig) {
String id = map.getId() == null ? DEFAULT_ID
: map.getId();
- if (mBrightnessThrottlingDataMap.containsKey(id)) {
+ if (mBrightnessThrottlingDataMapByThrottlingId.containsKey(id)) {
throw new RuntimeException("Brightness throttling data with ID " + id
+ " already exists");
}
- mBrightnessThrottlingDataMap.put(id,
+ mBrightnessThrottlingDataMapByThrottlingId.put(id,
BrightnessThrottlingData.create(throttlingLevels));
}
}
@@ -1971,8 +1972,8 @@
));
}
if (refreshRates.size() == 0) {
- Slog.w(TAG, "RefreshRateThrottling: no valid throttling points fond for map, mapId="
- + id);
+ Slog.w(TAG, "RefreshRateThrottling: no valid throttling points found for map, "
+ + "mapId=" + id);
continue;
}
mRefreshRateThrottlingMap.put(id, refreshRates);
@@ -3077,7 +3078,7 @@
/**
- * Creates multiple teperature based throttling levels of brightness
+ * Creates multiple temperature based throttling levels of brightness
*/
public static BrightnessThrottlingData create(List<ThrottlingLevel> throttlingLevels) {
if (throttlingLevels == null || throttlingLevels.size() == 0) {
@@ -3120,15 +3121,6 @@
return new BrightnessThrottlingData(throttlingLevels);
}
- static public BrightnessThrottlingData create(BrightnessThrottlingData other) {
- if (other == null) {
- return null;
- }
-
- return BrightnessThrottlingData.create(other.throttlingLevels);
- }
-
-
@Override
public String toString() {
return "BrightnessThrottlingData{"
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index f5859ee..2322e03 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -505,7 +505,7 @@
private DisplayDeviceConfig mDisplayDeviceConfig;
- // Identifiers for suspend blocker acuisition requests
+ // Identifiers for suspend blocker acquisition requests
private final String mSuspendBlockerIdUnfinishedBusiness;
private final String mSuspendBlockerIdOnStateChanged;
private final String mSuspendBlockerIdProxPositive;
@@ -515,6 +515,7 @@
private boolean mIsEnabled;
private boolean mIsInTransition;
+ // The id of the brightness throttling policy that should be used.
private String mBrightnessThrottlingDataId;
// DPCs following the brightness of this DPC. This is used in concurrent displays mode - there
@@ -905,14 +906,15 @@
loadNitBasedBrightnessSetting();
/// Since the underlying display-device changed, we really don't know the
- // last command that was sent to change it's state. Lets assume it is unknown so
+ // last command that was sent to change it's state. Let's assume it is unknown so
// that we trigger a change immediately.
mPowerState.resetScreenState();
} else if (!mBrightnessThrottlingDataId.equals(brightnessThrottlingDataId)) {
changed = true;
mBrightnessThrottlingDataId = brightnessThrottlingDataId;
- mBrightnessThrottler.resetThrottlingData(
- config.getBrightnessThrottlingData(mBrightnessThrottlingDataId),
+ mBrightnessThrottler.loadBrightnessThrottlingDataFromDisplayDeviceConfig(
+ config.getBrightnessThrottlingDataMapByThrottlingId(),
+ mBrightnessThrottlingDataId,
mUniqueDisplayId);
}
if (mIsEnabled != isEnabled || mIsInTransition != isInTransition) {
@@ -981,9 +983,9 @@
sdrBrightness, maxDesiredHdrSdrRatio);
}
});
- mBrightnessThrottler.resetThrottlingData(
- mDisplayDeviceConfig.getBrightnessThrottlingData(mBrightnessThrottlingDataId),
- mUniqueDisplayId);
+ mBrightnessThrottler.loadBrightnessThrottlingDataFromDisplayDeviceConfig(
+ mDisplayDeviceConfig.getBrightnessThrottlingDataMapByThrottlingId(),
+ mBrightnessThrottlingDataId, mUniqueDisplayId);
}
private void sendUpdatePowerState() {
@@ -2116,11 +2118,11 @@
final DisplayDevice device = mLogicalDisplay.getPrimaryDisplayDeviceLocked();
final DisplayDeviceConfig ddConfig = device.getDisplayDeviceConfig();
return new BrightnessThrottler(mHandler,
- ddConfig.getBrightnessThrottlingData(mBrightnessThrottlingDataId),
() -> {
sendUpdatePowerState();
postBrightnessChangeRunnable();
- }, mUniqueDisplayId);
+ }, mUniqueDisplayId, mLogicalDisplay.getBrightnessThrottlingDataIdLocked(),
+ ddConfig.getBrightnessThrottlingDataMapByThrottlingId());
}
private void blockScreenOn() {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java
index 8ce4b66..d2af88b 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController2.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController2.java
@@ -400,6 +400,7 @@
private boolean mIsEnabled;
private boolean mIsInTransition;
+ // The id of the brightness throttling policy that should be used.
private String mBrightnessThrottlingDataId;
// DPCs following the brightness of this DPC. This is used in concurrent displays mode - there
@@ -722,14 +723,15 @@
mDisplayPowerProximityStateController.notifyDisplayDeviceChanged(config);
// Since the underlying display-device changed, we really don't know the
- // last command that was sent to change it's state. Lets assume it is unknown so
+ // last command that was sent to change it's state. Let's assume it is unknown so
// that we trigger a change immediately.
mPowerState.resetScreenState();
} else if (!mBrightnessThrottlingDataId.equals(brightnessThrottlingDataId)) {
changed = true;
mBrightnessThrottlingDataId = brightnessThrottlingDataId;
- mBrightnessThrottler.resetThrottlingData(
- config.getBrightnessThrottlingData(mBrightnessThrottlingDataId),
+ mBrightnessThrottler.loadBrightnessThrottlingDataFromDisplayDeviceConfig(
+ config.getBrightnessThrottlingDataMapByThrottlingId(),
+ mBrightnessThrottlingDataId,
mUniqueDisplayId);
}
if (mIsEnabled != isEnabled || mIsInTransition != isInTransition) {
@@ -795,9 +797,9 @@
sdrBrightness, maxDesiredHdrSdrRatio);
}
});
- mBrightnessThrottler.resetThrottlingData(
- mDisplayDeviceConfig.getBrightnessThrottlingData(mBrightnessThrottlingDataId),
- mUniqueDisplayId);
+ mBrightnessThrottler.loadBrightnessThrottlingDataFromDisplayDeviceConfig(
+ mDisplayDeviceConfig.getBrightnessThrottlingDataMapByThrottlingId(),
+ mBrightnessThrottlingDataId, mUniqueDisplayId);
}
private void sendUpdatePowerState() {
@@ -1757,11 +1759,11 @@
final DisplayDevice device = mLogicalDisplay.getPrimaryDisplayDeviceLocked();
final DisplayDeviceConfig ddConfig = device.getDisplayDeviceConfig();
return new BrightnessThrottler(mHandler,
- ddConfig.getBrightnessThrottlingData(mBrightnessThrottlingDataId),
() -> {
sendUpdatePowerState();
postBrightnessChangeRunnable();
- }, mUniqueDisplayId);
+ }, mUniqueDisplayId, mLogicalDisplay.getBrightnessThrottlingDataIdLocked(),
+ ddConfig.getBrightnessThrottlingDataMapByThrottlingId());
}
private void blockScreenOn() {
diff --git a/services/core/java/com/android/server/display/layout/Layout.java b/services/core/java/com/android/server/display/layout/Layout.java
index f86ee24..634f31d 100644
--- a/services/core/java/com/android/server/display/layout/Layout.java
+++ b/services/core/java/com/android/server/display/layout/Layout.java
@@ -338,7 +338,9 @@
}
/**
- * @return The ID of the brightness throttling map that this display should use.
+ * Gets the id of the brightness throttling map that should be used.
+ * @return The ID of the brightness throttling map that this display should use, null if
+ * unspecified, will fall back to default.
*/
public String getBrightnessThrottlingMapId() {
return mBrightnessThrottlingMapId;
diff --git a/services/core/java/com/android/server/inputmethod/HandwritingModeController.java b/services/core/java/com/android/server/inputmethod/HandwritingModeController.java
index bb1a445..effef47 100644
--- a/services/core/java/com/android/server/inputmethod/HandwritingModeController.java
+++ b/services/core/java/com/android/server/inputmethod/HandwritingModeController.java
@@ -37,6 +37,7 @@
import android.view.InputEvent;
import android.view.InputEventReceiver;
import android.view.MotionEvent;
+import android.view.PointerIcon;
import android.view.SurfaceControl;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
@@ -273,6 +274,9 @@
}
mHandwritingSurface.startIntercepting(imePid, imeUid);
+ // Unset the pointer icon for the stylus in case the app had set it.
+ InputManagerGlobal.getInstance().setPointerIconType(PointerIcon.TYPE_NOT_SPECIFIED);
+
return new HandwritingSession(mCurrentRequestId, mHandwritingSurface.getInputChannel(),
mHandwritingBuffer);
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 81cca50..8707059 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -6625,20 +6625,15 @@
|| r.getImportance() == IMPORTANCE_NONE)) {
// Increase the importance of foreground service notifications unless the user had
// an opinion otherwise (and the channel hasn't yet shown a fg service).
- if (TextUtils.isEmpty(channelId)
- || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
- r.setSystemImportance(IMPORTANCE_LOW);
- } else {
- channel.setImportance(IMPORTANCE_LOW);
- r.setSystemImportance(IMPORTANCE_LOW);
- if (!fgServiceShown) {
- channel.unlockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
- channel.setFgServiceShown(true);
- }
- mPreferencesHelper.updateNotificationChannel(
- pkg, notificationUid, channel, false);
- r.updateNotificationChannel(channel);
+ channel.setImportance(IMPORTANCE_LOW);
+ r.setSystemImportance(IMPORTANCE_LOW);
+ if (!fgServiceShown) {
+ channel.unlockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
+ channel.setFgServiceShown(true);
}
+ mPreferencesHelper.updateNotificationChannel(
+ pkg, notificationUid, channel, false);
+ r.updateNotificationChannel(channel);
} else if (!fgServiceShown && !TextUtils.isEmpty(channelId)
&& !NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
channel.setFgServiceShown(true);
diff --git a/services/core/java/com/android/server/security/rkp/RemoteProvisioningRegistration.java b/services/core/java/com/android/server/security/rkp/RemoteProvisioningRegistration.java
index 2d3ede0..f586126 100644
--- a/services/core/java/com/android/server/security/rkp/RemoteProvisioningRegistration.java
+++ b/services/core/java/com/android/server/security/rkp/RemoteProvisioningRegistration.java
@@ -70,12 +70,14 @@
Log.i(TAG, "Operation cancelled for client " + mCallback.hashCode());
wrapCallback(mCallback::onCancel);
} else if (e instanceof RkpProxyException) {
- Log.e(TAG, "RKP error fetching key for client " + mCallback.hashCode(), e);
+ Log.e(TAG, "RKP error fetching key for client " + mCallback.hashCode() + ": "
+ + e.getMessage());
RkpProxyException rkpException = (RkpProxyException) e;
wrapCallback(() -> mCallback.onError(toGetKeyError(rkpException),
e.getMessage()));
} else {
- Log.e(TAG, "Error fetching key for client " + mCallback.hashCode(), e);
+ Log.e(TAG, "Unknown error fetching key for client " + mCallback.hashCode() + ": "
+ + e.getMessage());
wrapCallback(() -> mCallback.onError(IGetKeyCallback.ErrorCode.ERROR_UNKNOWN,
e.getMessage()));
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 5f56923..8346e7c 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -4068,7 +4068,7 @@
}
void finishRelaunching() {
- mLetterboxUiController.setRelauchingAfterRequestedOrientationChanged(false);
+ mLetterboxUiController.setRelaunchingAfterRequestedOrientationChanged(false);
mTaskSupervisor.getActivityMetricsLogger().notifyActivityRelaunched(this);
if (mPendingRelaunchCount > 0) {
@@ -9500,7 +9500,7 @@
mRelaunchReason = RELAUNCH_REASON_NONE;
}
if (isRequestedOrientationChanged) {
- mLetterboxUiController.setRelauchingAfterRequestedOrientationChanged(true);
+ mLetterboxUiController.setRelaunchingAfterRequestedOrientationChanged(true);
}
if (mState == PAUSING) {
// A little annoying: we are waiting for this activity to finish pausing. Let's not
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index 6773bcd..e447049 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -487,7 +487,7 @@
// The verdict changed from allow (resultIfPiSenderAllowsBal) to block, PI sender
// default change is on (otherwise we would have fallen into if above) and we'd
// allow if it were off
- Slog.wtf(TAG, "Without BAL hardening this activity start would NOT be allowed!"
+ Slog.wtf(TAG, "Without BAL hardening this activity start would be allowed!"
+ stateDumpLog);
}
}
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index b0c384d..93233dd 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -50,6 +50,7 @@
import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE;
import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE;
import static android.view.WindowManager.PROPERTY_COMPAT_ENABLE_FAKE_FOCUS;
+import static android.view.WindowManager.PROPERTY_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED;
import static android.view.WindowManager.PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION;
import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__BOTTOM;
@@ -235,9 +236,14 @@
private final Boolean mBooleanPropertyIgnoreRequestedOrientation;
@Nullable
+ private final Boolean mBooleanPropertyIgnoreOrientationRequestWhenLoopDetected;
+
+ @Nullable
private final Boolean mBooleanPropertyFakeFocus;
- private boolean mIsRelauchingAfterRequestedOrientationChanged;
+ private boolean mIsRelaunchingAfterRequestedOrientationChanged;
+
+ private boolean mLastShouldShowLetterboxUi;
private boolean mDoubleTapEvent;
@@ -253,6 +259,10 @@
readComponentProperty(packageManager, mActivityRecord.packageName,
mLetterboxConfiguration::isPolicyForIgnoringRequestedOrientationEnabled,
PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION);
+ mBooleanPropertyIgnoreOrientationRequestWhenLoopDetected =
+ readComponentProperty(packageManager, mActivityRecord.packageName,
+ mLetterboxConfiguration::isPolicyForIgnoringRequestedOrientationEnabled,
+ PROPERTY_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED);
mBooleanPropertyFakeFocus =
readComponentProperty(packageManager, mActivityRecord.packageName,
mLetterboxConfiguration::isCompatFakeFocusEnabled,
@@ -387,7 +397,7 @@
::isPolicyForIgnoringRequestedOrientationEnabled,
mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled,
mBooleanPropertyIgnoreRequestedOrientation)) {
- if (mIsRelauchingAfterRequestedOrientationChanged) {
+ if (mIsRelaunchingAfterRequestedOrientationChanged) {
Slog.w(TAG, "Ignoring orientation update to "
+ screenOrientationToString(requestedOrientation)
+ " due to relaunching after setRequestedOrientation for "
@@ -422,6 +432,8 @@
*
* <p>This treatment is enabled when the following conditions are met:
* <ul>
+ * <li>Flag gating the treatment is enabled
+ * <li>Opt-out component property isn't enabled
* <li>Per-app override is enabled
* <li>App has requested orientation more than 2 times within 1-second
* timer and activity is not letterboxed for fixed orientation
@@ -429,7 +441,11 @@
*/
@VisibleForTesting
boolean shouldIgnoreOrientationRequestLoop() {
- if (!mIsOverrideEnableCompatIgnoreOrientationRequestWhenLoopDetectedEnabled) {
+ if (!shouldEnableWithOptInOverrideAndOptOutProperty(
+ /* gatingCondition */ mLetterboxConfiguration
+ ::isPolicyForIgnoringRequestedOrientationEnabled,
+ mIsOverrideEnableCompatIgnoreOrientationRequestWhenLoopDetectedEnabled,
+ mBooleanPropertyIgnoreOrientationRequestWhenLoopDetected)) {
return false;
}
@@ -476,8 +492,8 @@
* Sets whether an activity is relaunching after the app has called {@link
* android.app.Activity#setRequestedOrientation}.
*/
- void setRelauchingAfterRequestedOrientationChanged(boolean isRelaunching) {
- mIsRelauchingAfterRequestedOrientationChanged = isRelaunching;
+ void setRelaunchingAfterRequestedOrientationChanged(boolean isRelaunching) {
+ mIsRelaunchingAfterRequestedOrientationChanged = isRelaunching;
}
/**
@@ -1154,12 +1170,28 @@
@VisibleForTesting
boolean shouldShowLetterboxUi(WindowState mainWindow) {
- return (mActivityRecord.isInLetterboxAnimation() || isSurfaceVisible(mainWindow))
+ if (mIsRelaunchingAfterRequestedOrientationChanged || !isSurfaceReadyToShow(mainWindow)) {
+ return mLastShouldShowLetterboxUi;
+ }
+
+ final boolean shouldShowLetterboxUi =
+ (mActivityRecord.isInLetterboxAnimation() || isSurfaceVisible(mainWindow))
&& mainWindow.areAppWindowBoundsLetterboxed()
// Check for FLAG_SHOW_WALLPAPER explicitly instead of using
// WindowContainer#showWallpaper because the later will return true when this
// activity is using blurred wallpaper for letterbox background.
&& (mainWindow.getAttrs().flags & FLAG_SHOW_WALLPAPER) == 0;
+
+ mLastShouldShowLetterboxUi = shouldShowLetterboxUi;
+
+ return shouldShowLetterboxUi;
+ }
+
+ @VisibleForTesting
+ boolean isSurfaceReadyToShow(WindowState mainWindow) {
+ return mainWindow.isDrawn() // Regular case
+ // Waiting for relayoutWindow to call preserveSurface
+ || mainWindow.isDragResizeChanged();
}
@VisibleForTesting
@@ -1297,6 +1329,10 @@
return null;
}
+ boolean getIsRelaunchingAfterRequestedOrientationChanged() {
+ return mIsRelaunchingAfterRequestedOrientationChanged;
+ }
+
private void adjustBoundsForTaskbar(final WindowState mainWindow, final Rect bounds) {
// Rounded corners should be displayed above the taskbar. When taskbar is hidden,
// an insets frame is equal to a navigation bar which shouldn't affect position of
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 23934e0..736f489 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -5230,8 +5230,17 @@
if (surfaceInsetsChanged) {
mLastSurfaceInsets.set(mAttrs.surfaceInsets);
}
- if (surfaceSizeChanged && mWinAnimator.getShown() && !canPlayMoveAnimation()
- && okToDisplay() && mSyncState == SYNC_STATE_NONE) {
+ final boolean surfaceResizedWithoutMoveAnimation = surfaceSizeChanged
+ && mWinAnimator.getShown() && !canPlayMoveAnimation() && okToDisplay()
+ && mSyncState == SYNC_STATE_NONE;
+ final ActivityRecord activityRecord = getActivityRecord();
+ // If this window belongs to an activity that is relaunching due to an orientation
+ // change then delay the position update until it has redrawn to avoid any flickers.
+ final boolean isLetterboxedAndRelaunching = activityRecord != null
+ && activityRecord.areBoundsLetterboxed()
+ && activityRecord.mLetterboxUiController
+ .getIsRelaunchingAfterRequestedOrientationChanged();
+ if (surfaceResizedWithoutMoveAnimation || isLetterboxedAndRelaunching) {
applyWithNextDraw(mSetSurfacePositionConsumer);
} else {
mSetSurfacePositionConsumer.accept(t);
diff --git a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
index dce7b87..bbebbf2 100644
--- a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
@@ -40,11 +40,13 @@
implements ProviderSession.ProviderInternalCallback<Void> {
private static final String TAG = "GetRequestSession";
- public ClearRequestSession(Context context, int userId, int callingUid,
+ public ClearRequestSession(Context context, RequestSession.SessionLifetime sessionCallback,
+ Object lock, int userId, int callingUid,
IClearCredentialStateCallback callback, ClearCredentialStateRequest request,
CallingAppInfo callingAppInfo, CancellationSignal cancellationSignal,
long startedTimestamp) {
- super(context, userId, callingUid, request, callback, RequestInfo.TYPE_UNDEFINED,
+ super(context, sessionCallback, lock, userId, callingUid, request, callback,
+ RequestInfo.TYPE_UNDEFINED,
callingAppInfo, cancellationSignal, startedTimestamp);
}
diff --git a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
index 98dc8ab..4c456a8 100644
--- a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
@@ -49,13 +49,15 @@
implements ProviderSession.ProviderInternalCallback<CreateCredentialResponse> {
private static final String TAG = "CreateRequestSession";
- CreateRequestSession(@NonNull Context context, int userId, int callingUid,
+ CreateRequestSession(@NonNull Context context, RequestSession.SessionLifetime sessionCallback,
+ Object lock, int userId, int callingUid,
CreateCredentialRequest request,
ICreateCredentialCallback callback,
CallingAppInfo callingAppInfo,
CancellationSignal cancellationSignal,
long startedTimestamp) {
- super(context, userId, callingUid, request, callback, RequestInfo.TYPE_CREATE,
+ super(context, sessionCallback, lock, userId, callingUid, request, callback,
+ RequestInfo.TYPE_CREATE,
callingAppInfo, cancellationSignal, startedTimestamp);
}
@@ -83,6 +85,7 @@
@Override
protected void launchUiWithProviderData(ArrayList<ProviderData> providerDataList) {
mRequestSessionMetric.collectUiCallStartTime(System.nanoTime());
+ mCredentialManagerUi.setStatus(CredentialManagerUi.UiStatus.USER_INTERACTION);
try {
mClientCallback.onPendingIntent(mCredentialManagerUi.createPendingIntent(
RequestInfo.newCreateRequestInfo(
@@ -93,6 +96,7 @@
providerDataList));
} catch (RemoteException e) {
mRequestSessionMetric.collectUiReturnedFinalPhase(/*uiReturned=*/ false);
+ mCredentialManagerUi.setStatus(CredentialManagerUi.UiStatus.TERMINATED);
respondToClientWithErrorAndFinish(
CreateCredentialException.TYPE_UNKNOWN,
"Unable to invoke selector");
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
index de06d44..ae6eaf0 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
@@ -33,7 +33,6 @@
import android.credentials.ClearCredentialStateRequest;
import android.credentials.CreateCredentialException;
import android.credentials.CreateCredentialRequest;
-import android.credentials.CredentialManager;
import android.credentials.CredentialOption;
import android.credentials.CredentialProviderInfo;
import android.credentials.GetCredentialException;
@@ -50,6 +49,7 @@
import android.credentials.ui.IntentFactory;
import android.os.Binder;
import android.os.CancellationSignal;
+import android.os.IBinder;
import android.os.ICancellationSignal;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -70,9 +70,11 @@
import com.android.server.infra.SecureSettingsServiceNameResolver;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@@ -102,6 +104,13 @@
private final SparseArray<List<CredentialManagerServiceImpl>> mSystemServicesCacheList =
new SparseArray<>();
+ /** Cache of all ongoing request sessions per user id. */
+ @GuardedBy("mLock")
+ private final SparseArray<Map<IBinder, RequestSession>> mRequestSessions =
+ new SparseArray<>();
+
+ private final SessionManager mSessionManager = new SessionManager();
+
public CredentialManagerService(@NonNull Context context) {
super(
context,
@@ -331,7 +340,7 @@
@NonNull
private Set<Pair<CredentialOption, CredentialDescriptionRegistry.FilterResult>>
- getFilteredResultFromRegistry(List<CredentialOption> options) {
+ getFilteredResultFromRegistry(List<CredentialOption> options) {
// Session for active/provisioned credential descriptions;
CredentialDescriptionRegistry registry =
CredentialDescriptionRegistry.forUser(UserHandle.getCallingUserId());
@@ -389,14 +398,6 @@
return providerSessions;
}
- private List<CredentialProviderInfo> getServicesForCredentialDescription(int userId) {
- return CredentialProviderInfoFactory.getCredentialProviderServices(
- mContext,
- userId,
- CredentialManager.PROVIDER_FILTER_ALL_PROVIDERS,
- new HashSet<>());
- }
-
@Override
@GuardedBy("CredentialDescriptionRegistry.sLock")
public void onUserStopped(@NonNull TargetUser user) {
@@ -448,6 +449,8 @@
final GetRequestSession session =
new GetRequestSession(
getContext(),
+ mSessionManager,
+ mLock,
userId,
callingUid,
callback,
@@ -455,6 +458,7 @@
constructCallingAppInfo(callingPackage, userId, request.getOrigin()),
CancellationSignal.fromTransport(cancelTransport),
timestampBegan);
+ addSessionLocked(userId, session);
List<ProviderSession> providerSessions =
prepareProviderSessions(request, session);
@@ -499,6 +503,8 @@
final PrepareGetRequestSession session =
new PrepareGetRequestSession(
getContext(),
+ mSessionManager,
+ mLock,
userId,
callingUid,
getCredentialCallback,
@@ -515,8 +521,8 @@
// TODO: fix
prepareGetCredentialCallback.onResponse(
new PrepareGetCredentialResponseInternal(
- false, null,
- false, false, null));
+ false, null,
+ false, false, null));
} catch (RemoteException e) {
Log.i(
TAG,
@@ -540,10 +546,10 @@
List<CredentialOption> optionsThatRequireActiveCredentials =
request.getCredentialOptions().stream()
.filter(credentialOption -> credentialOption
- .getCredentialRetrievalData()
- .getStringArrayList(
- CredentialOption
- .SUPPORTED_ELEMENT_KEYS) != null)
+ .getCredentialRetrievalData()
+ .getStringArrayList(
+ CredentialOption
+ .SUPPORTED_ELEMENT_KEYS) != null)
.toList();
List<CredentialOption> optionsThatDoNotRequireActiveCredentials =
@@ -614,6 +620,8 @@
final CreateRequestSession session =
new CreateRequestSession(
getContext(),
+ mSessionManager,
+ mLock,
userId,
callingUid,
request,
@@ -621,6 +629,7 @@
constructCallingAppInfo(callingPackage, userId, request.getOrigin()),
CancellationSignal.fromTransport(cancelTransport),
timestampBegan);
+ addSessionLocked(userId, session);
processCreateCredential(request, callback, session);
return cancelTransport;
@@ -775,6 +784,19 @@
mContext, userId, providerFilter, getEnabledProviders());
}
+ @Override
+ public boolean isServiceEnabled() {
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ return DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_CREDENTIAL,
+ CredentialManager.DEVICE_CONFIG_ENABLE_CREDENTIAL_MANAGER,
+ false);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
@SuppressWarnings("GuardedBy") // ErrorProne requires service.mLock which is the same
// this.mLock
private Set<ComponentName> getEnabledProviders() {
@@ -815,6 +837,8 @@
final ClearRequestSession session =
new ClearRequestSession(
getContext(),
+ mSessionManager,
+ mLock,
userId,
callingUid,
callback,
@@ -822,6 +846,7 @@
constructCallingAppInfo(callingPackage, userId, null),
CancellationSignal.fromTransport(cancelTransport),
timestampBegan);
+ addSessionLocked(userId, session);
// Initiate all provider sessions
// TODO: Determine if provider needs to have clear capability in their manifest
@@ -905,6 +930,13 @@
}
}
+ private void addSessionLocked(@UserIdInt int userId,
+ RequestSession requestSession) {
+ synchronized (mLock) {
+ mSessionManager.addSession(userId, requestSession.mRequestId, requestSession);
+ }
+ }
+
private void enforceCallingPackage(String callingPackage, int callingUid) {
int packageUid;
PackageManager pm = mContext.createContextAsUser(
@@ -919,4 +951,23 @@
throw new SecurityException(callingPackage + " does not belong to uid " + callingUid);
}
}
+
+ private class SessionManager implements RequestSession.SessionLifetime {
+ @Override
+ @GuardedBy("mLock")
+ public void onFinishRequestSession(@UserIdInt int userId, IBinder token) {
+ Log.i(TAG, "In onFinishRequestSession");
+ if (mRequestSessions.get(userId) != null) {
+ mRequestSessions.get(userId).remove(token);
+ }
+ }
+
+ @GuardedBy("mLock")
+ public void addSession(int userId, IBinder token, RequestSession requestSession) {
+ if (mRequestSessions.get(userId) == null) {
+ mRequestSessions.put(userId, new HashMap<>());
+ }
+ mRequestSessions.get(userId).put(token, requestSession);
+ }
+ }
}
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
index 546c37f..e16d48e 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
@@ -30,6 +30,7 @@
import android.credentials.ui.UserSelectionDialogResult;
import android.os.Bundle;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.ResultReceiver;
import android.service.credentials.CredentialProviderInfoFactory;
@@ -50,6 +51,20 @@
@NonNull private final Context mContext;
// TODO : Use for starting the activity for this user
private final int mUserId;
+
+ private UiStatus mStatus;
+
+ /** Creates intent that is ot be invoked to cancel an in-progress UI session. */
+ public Intent createCancelIntent(IBinder requestId, String packageName) {
+ return IntentFactory.createCancelUiIntent(requestId, /*shouldShowCancellationUi=*/ true,
+ packageName);
+ }
+
+ enum UiStatus {
+ IN_PROGRESS,
+ USER_INTERACTION,
+ NOT_STARTED, TERMINATED
+ }
@NonNull private final ResultReceiver mResultReceiver = new ResultReceiver(
new Handler(Looper.getMainLooper())) {
@Override
@@ -61,6 +76,7 @@
private void handleUiResult(int resultCode, Bundle resultData) {
switch (resultCode) {
case UserSelectionDialogResult.RESULT_CODE_DIALOG_COMPLETE_WITH_SELECTION:
+ mStatus = UiStatus.IN_PROGRESS;
UserSelectionDialogResult selection = UserSelectionDialogResult
.fromResultData(resultData);
if (selection != null) {
@@ -70,16 +86,20 @@
}
break;
case UserSelectionDialogResult.RESULT_CODE_DIALOG_USER_CANCELED:
+ mStatus = UiStatus.TERMINATED;
mCallbacks.onUiCancellation(/* isUserCancellation= */ true);
break;
case UserSelectionDialogResult.RESULT_CODE_CANCELED_AND_LAUNCHED_SETTINGS:
+ mStatus = UiStatus.TERMINATED;
mCallbacks.onUiCancellation(/* isUserCancellation= */ false);
break;
case UserSelectionDialogResult.RESULT_CODE_DATA_PARSING_FAILURE:
+ mStatus = UiStatus.TERMINATED;
mCallbacks.onUiSelectorInvocationFailure();
break;
default:
Slog.i(TAG, "Unknown error code returned from the UI");
+ mStatus = UiStatus.IN_PROGRESS;
mCallbacks.onUiSelectorInvocationFailure();
break;
}
@@ -103,6 +123,17 @@
mContext = context;
mUserId = userId;
mCallbacks = callbacks;
+ mStatus = UiStatus.IN_PROGRESS;
+ }
+
+ /** Set status for credential manager UI */
+ public void setStatus(UiStatus status) {
+ mStatus = status;
+ }
+
+ /** Returns status for credential manager UI */
+ public UiStatus getStatus() {
+ return mStatus;
}
/**
diff --git a/services/credentials/java/com/android/server/credentials/GetRequestSession.java b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
index c0c7be9..2548bd8 100644
--- a/services/credentials/java/com/android/server/credentials/GetRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
@@ -45,12 +45,13 @@
IGetCredentialCallback, GetCredentialResponse>
implements ProviderSession.ProviderInternalCallback<GetCredentialResponse> {
private static final String TAG = "GetRequestSession";
- public GetRequestSession(Context context, int userId, int callingUid,
+ public GetRequestSession(Context context, RequestSession.SessionLifetime sessionCallback,
+ Object lock, int userId, int callingUid,
IGetCredentialCallback callback, GetCredentialRequest request,
CallingAppInfo callingAppInfo, CancellationSignal cancellationSignal,
long startedTimestamp) {
- super(context, userId, callingUid, request, callback, RequestInfo.TYPE_GET,
- callingAppInfo, cancellationSignal, startedTimestamp);
+ super(context, sessionCallback, lock, userId, callingUid, request, callback,
+ RequestInfo.TYPE_GET, callingAppInfo, cancellationSignal, startedTimestamp);
int numTypes = (request.getCredentialOptions().stream()
.map(CredentialOption::getType).collect(
Collectors.toSet())).size(); // Dedupe type strings
@@ -81,6 +82,7 @@
@Override
protected void launchUiWithProviderData(ArrayList<ProviderData> providerDataList) {
mRequestSessionMetric.collectUiCallStartTime(System.nanoTime());
+ mCredentialManagerUi.setStatus(CredentialManagerUi.UiStatus.USER_INTERACTION);
try {
mClientCallback.onPendingIntent(mCredentialManagerUi.createPendingIntent(
RequestInfo.newGetRequestInfo(
@@ -88,6 +90,7 @@
providerDataList));
} catch (RemoteException e) {
mRequestSessionMetric.collectUiReturnedFinalPhase(/*uiReturned=*/ false);
+ mCredentialManagerUi.setStatus(CredentialManagerUi.UiStatus.TERMINATED);
respondToClientWithErrorAndFinish(
GetCredentialException.TYPE_UNKNOWN, "Unable to instantiate selector");
}
diff --git a/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java b/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java
index c4e480a..88f3e6c 100644
--- a/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java
@@ -49,14 +49,13 @@
private final IPrepareGetCredentialCallback mPrepareGetCredentialCallback;
- public PrepareGetRequestSession(Context context, int userId, int callingUid,
- IGetCredentialCallback callback,
- GetCredentialRequest request,
- CallingAppInfo callingAppInfo,
- CancellationSignal cancellationSignal, long startedTimestamp,
- IPrepareGetCredentialCallback prepareGetCredentialCallback) {
- super(context, userId, callingUid, callback, request, callingAppInfo, cancellationSignal,
- startedTimestamp);
+ public PrepareGetRequestSession(Context context,
+ RequestSession.SessionLifetime sessionCallback, Object lock, int userId,
+ int callingUid, IGetCredentialCallback getCredCallback, GetCredentialRequest request,
+ CallingAppInfo callingAppInfo, CancellationSignal cancellationSignal,
+ long startedTimestamp, IPrepareGetCredentialCallback prepareGetCredentialCallback) {
+ super(context, sessionCallback, lock, userId, callingUid, getCredCallback, request,
+ callingAppInfo, cancellationSignal, startedTimestamp);
int numTypes = (request.getCredentialOptions().stream()
.map(CredentialOption::getType).collect(
Collectors.toSet())).size(); // Dedupe type strings
diff --git a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java
index 1b736e0..eaf58f1 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java
@@ -126,7 +126,8 @@
protected void invokeSession() {
if (mRemoteCredentialService != null) {
startCandidateMetrics();
- mRemoteCredentialService.onClearCredentialState(mProviderRequest, this);
+ mProviderCancellationSignal =
+ mRemoteCredentialService.onClearCredentialState(mProviderRequest, this);
}
}
}
diff --git a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
index bef045f..c657e3b 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
@@ -236,7 +236,8 @@
protected void invokeSession() {
if (mRemoteCredentialService != null) {
startCandidateMetrics();
- mRemoteCredentialService.onCreateCredential(mProviderRequest, this);
+ mProviderCancellationSignal =
+ mRemoteCredentialService.onCreateCredential(mProviderRequest, this);
}
}
diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
index 427a894..9c9c0c2 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
@@ -302,7 +302,9 @@
protected void invokeSession() {
if (mRemoteCredentialService != null) {
startCandidateMetrics();
- mRemoteCredentialService.onBeginGetCredential(mProviderRequest, this);
+ mProviderCancellationSignal =
+ mRemoteCredentialService.onBeginGetCredential(mProviderRequest, this);
+ boolean foundSig = mProviderCancellationSignal == null;
}
}
diff --git a/services/credentials/java/com/android/server/credentials/ProviderSession.java b/services/credentials/java/com/android/server/credentials/ProviderSession.java
index 8c0e1c1..d165756 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderSession.java
@@ -30,6 +30,7 @@
import android.os.ICancellationSignal;
import android.os.RemoteException;
import android.util.Log;
+import android.util.Slog;
import com.android.server.credentials.metrics.ProviderSessionMetric;
@@ -189,7 +190,7 @@
}
setStatus(Status.CANCELED);
} catch (RemoteException e) {
- Log.i(TAG, "Issue while cancelling provider session: " + e.getMessage());
+ Slog.e(TAG, "Issue while cancelling provider session: ", e);
}
}
diff --git a/services/credentials/java/com/android/server/credentials/RequestSession.java b/services/credentials/java/com/android/server/credentials/RequestSession.java
index cfb9ad4..ed175ed 100644
--- a/services/credentials/java/com/android/server/credentials/RequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/RequestSession.java
@@ -20,6 +20,7 @@
import android.annotation.UserIdInt;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.credentials.CredentialProviderInfo;
import android.credentials.ui.ProviderData;
import android.credentials.ui.UserSelectionDialogResult;
@@ -29,8 +30,10 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.service.credentials.CallingAppInfo;
import android.util.Log;
+import android.util.Slog;
import com.android.internal.R;
import com.android.server.credentials.metrics.ApiName;
@@ -39,8 +42,8 @@
import com.android.server.credentials.metrics.RequestSessionMetric;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
/**
* Base class of a request session, that listens to UI events. This class must be extended
@@ -49,6 +52,11 @@
abstract class RequestSession<T, U, V> implements CredentialManagerUi.CredentialManagerUiCallback {
private static final String TAG = "RequestSession";
+ public interface SessionLifetime {
+ /** Called when the user makes a selection. */
+ void onFinishRequestSession(@UserIdInt int userId, IBinder token);
+ }
+
// TODO: Revise access levels of attributes
@NonNull
protected final T mClientRequest;
@@ -72,10 +80,14 @@
@NonNull
protected final CancellationSignal mCancellationSignal;
- protected final Map<String, ProviderSession> mProviders = new HashMap<>();
+ protected final Map<String, ProviderSession> mProviders = new ConcurrentHashMap<>();
protected final RequestSessionMetric mRequestSessionMetric = new RequestSessionMetric();
protected final String mHybridService;
+ protected final Object mLock;
+
+ protected final SessionLifetime mSessionCallback;
+
@NonNull
protected RequestSessionStatus mRequestSessionStatus =
RequestSessionStatus.IN_PROGRESS;
@@ -91,11 +103,15 @@
}
protected RequestSession(@NonNull Context context,
- @UserIdInt int userId, int callingUid, @NonNull T clientRequest, U clientCallback,
+ RequestSession.SessionLifetime sessionCallback,
+ Object lock, @UserIdInt int userId, int callingUid,
+ @NonNull T clientRequest, U clientCallback,
@NonNull String requestType,
CallingAppInfo callingAppInfo,
CancellationSignal cancellationSignal, long timestampStarted) {
mContext = context;
+ mLock = lock;
+ mSessionCallback = sessionCallback;
mUserId = userId;
mCallingUid = callingUid;
mClientRequest = clientRequest;
@@ -111,6 +127,32 @@
R.string.config_defaultCredentialManagerHybridService);
mRequestSessionMetric.collectInitialPhaseMetricInfo(timestampStarted, mRequestId,
mCallingUid, ApiName.getMetricCodeFromRequestInfo(mRequestType));
+ setCancellationListener();
+ }
+
+ private void setCancellationListener() {
+ mCancellationSignal.setOnCancelListener(
+ () -> {
+ boolean isUiActive = maybeCancelUi();
+ finishSession(!isUiActive);
+ }
+ );
+ }
+
+ private boolean maybeCancelUi() {
+ if (mCredentialManagerUi.getStatus()
+ == CredentialManagerUi.UiStatus.USER_INTERACTION) {
+ final long originalCallingUidToken = Binder.clearCallingIdentity();
+ try {
+ mContext.startActivityAsUser(mCredentialManagerUi.createCancelIntent(
+ mRequestId, mClientAppInfo.getPackageName())
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), UserHandle.of(mUserId));
+ return true;
+ } finally {
+ Binder.restoreCallingIdentity(originalCallingUidToken);
+ }
+ }
+ return false;
}
public abstract ProviderSession initiateProviderSession(CredentialProviderInfo providerInfo,
@@ -154,12 +196,19 @@
}
protected void finishSession(boolean propagateCancellation) {
- Log.i(TAG, "finishing session");
+ Slog.d(TAG, "finishing session with propagateCancellation " + propagateCancellation);
if (propagateCancellation) {
mProviders.values().forEach(ProviderSession::cancelProviderRemoteSession);
}
mRequestSessionStatus = RequestSessionStatus.COMPLETE;
mProviders.clear();
+ clearRequestSessionLocked();
+ }
+
+ private void clearRequestSessionLocked() {
+ synchronized (mLock) {
+ mSessionCallback.onFinishRequestSession(mUserId, mRequestId);
+ }
}
protected boolean isAnyProviderPending() {
@@ -194,7 +243,6 @@
ArrayList<ProviderData> providerDataList = getProviderDataForUi();
if (!providerDataList.isEmpty()) {
Log.i(TAG, "provider list not empty about to initiate ui");
- mRequestSessionMetric.logCandidatePhaseMetrics(mProviders);
launchUiWithProviderData(providerDataList);
}
}
@@ -204,9 +252,9 @@
Log.i(TAG, "In getProviderDataAndInitiateUi");
Log.i(TAG, "In getProviderDataAndInitiateUi providers size: " + mProviders.size());
ArrayList<ProviderData> providerDataList = new ArrayList<>();
+ mRequestSessionMetric.logCandidatePhaseMetrics(mProviders);
if (isSessionCancelled()) {
- mRequestSessionMetric.logCandidatePhaseMetrics(mProviders);
finishSession(/*propagateCancellation=*/true);
return providerDataList;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index a109dee..b215641 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -92,6 +92,8 @@
import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS;
import static android.app.AppOpsManager.OPSTR_SYSTEM_EXEMPT_FROM_SUSPENSION;
import static android.app.admin.DeviceAdminInfo.HEADLESS_DEVICE_OWNER_MODE_AFFILIATED;
+import static android.app.admin.DeviceAdminInfo.USES_POLICY_FORCE_LOCK;
+import static android.app.admin.DeviceAdminInfo.USES_POLICY_WIPE_DATA;
import static android.app.admin.DeviceAdminReceiver.ACTION_COMPLIANCE_ACKNOWLEDGEMENT_REQUIRED;
import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE;
import static android.app.admin.DevicePolicyIdentifiers.AUTO_TIMEZONE_POLICY;
@@ -439,6 +441,7 @@
import android.util.DebugUtils;
import android.util.IndentingPrintWriter;
import android.util.IntArray;
+import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
@@ -773,6 +776,14 @@
@EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
public static final long EXPLICIT_WIPE_BEHAVIOUR = 242193913L;
+ /**
+ * Apps targetting U+ should now expect that attempts to grant sensor permissions without
+ * authorisation will result in a security exception.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ public static final long THROW_SECURITY_EXCEPTION_FOR_SENSOR_PERMISSIONS = 277035314L;
+
// Only add to the end of the list. Do not change or rearrange these values, that will break
// historical data. Do not use negative numbers or zero, logger only handles positive
// integers.
@@ -2819,6 +2830,16 @@
return doAdmin;
}
+ ActiveAdmin getDefaultDeviceOwnerLocked(@UserIdInt int userId) {
+ ensureLocked();
+ ComponentName doComponent = mOwners.getDeviceOwnerComponent();
+ if (mOwners.getDeviceOwnerType(doComponent.getPackageName()) == DEFAULT_DEVICE_OWNER) {
+ ActiveAdmin doAdmin = getUserData(userId).mAdminMap.get(doComponent);
+ return doAdmin;
+ }
+ return null;
+ }
+
ActiveAdmin getProfileOwnerLocked(@UserIdInt int userId) {
ensureLocked();
final ComponentName poAdminComponent = mOwners.getProfileOwnerComponent(userId);
@@ -2848,6 +2869,18 @@
return getDeviceOwnerLocked(userId);
}
+ ActiveAdmin getProfileOwnerOrDefaultDeviceOwnerLocked(@UserIdInt int userId) {
+ ensureLocked();
+ // Try to find an admin which can use reqPolicy
+ final ComponentName poAdminComponent = mOwners.getProfileOwnerComponent(userId);
+
+ if (poAdminComponent != null) {
+ return getProfileOwnerLocked(userId);
+ }
+
+ return getDefaultDeviceOwnerLocked(userId);
+ }
+
@NonNull ActiveAdmin getParentOfAdminIfRequired(ActiveAdmin admin, boolean parent) {
Objects.requireNonNull(admin);
return parent ? admin.getParentActiveAdmin() : admin;
@@ -5337,9 +5370,12 @@
saveSettingsLocked(caller.getUserId());
});
+
+ //TODO(b/276855301): caller.getPackageName() will be null when the coexistence flags are
+ // turned off. Change back to caller.getPackageName once this API is unflagged.
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_PASSWORD_COMPLEXITY)
- .setAdmin(caller.getPackageName())
+ .setAdmin(admin.info.getPackageName())
.setInt(passwordComplexity)
.setBoolean(calledOnParent)
.write();
@@ -5974,8 +6010,13 @@
}
@Override
- public void lockNow(int flags, boolean parent) {
- final CallerIdentity caller = getCallerIdentity();
+ public void lockNow(int flags, String callerPackageName, boolean parent) {
+ CallerIdentity caller;
+ if (isPermissionCheckFlagEnabled()) {
+ caller = getCallerIdentity(callerPackageName);
+ } else {
+ caller = getCallerIdentity();
+ }
final int callingUserId = caller.getUserId();
ComponentName adminComponent = null;
@@ -5984,11 +6025,13 @@
// Make sure the caller has any active admin with the right policy or
// the required permission.
if (isPermissionCheckFlagEnabled()) {
- admin = getActiveAdminOrCheckPermissionsForCallerLocked(
- null,
- DeviceAdminInfo.USES_POLICY_FORCE_LOCK,
- parent,
- Set.of(MANAGE_DEVICE_POLICY_LOCK, LOCK_DEVICE));
+ admin = enforcePermissionAndGetEnforcingAdmin(
+ /* admin= */ null,
+ /* permission= */ MANAGE_DEVICE_POLICY_LOCK,
+ USES_POLICY_FORCE_LOCK,
+ caller.getPackageName(),
+ getAffectedUser(parent)
+ ).getActiveAdmin();
} else {
admin = getActiveAdminOrCheckPermissionForCallerLocked(
null,
@@ -7481,7 +7524,8 @@
if (isPolicyEngineForFinanceFlagEnabled()) {
EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin(
/*admin=*/ null,
- MANAGE_DEVICE_POLICY_WIPE_DATA,
+ /*permission= */ MANAGE_DEVICE_POLICY_WIPE_DATA,
+ USES_POLICY_WIPE_DATA,
caller.getPackageName(),
factoryReset ? UserHandle.USER_ALL : getAffectedUser(calledOnParentInstance));
admin = enforcingAdmin.getActiveAdmin();
@@ -8511,7 +8555,7 @@
isProfileOwnerOfOrganizationOwnedDevice(caller));
} else {
Preconditions.checkCallAuthorization(isProfileOwner(caller)
- || isDeviceOwner(caller));
+ || isDefaultDeviceOwner(caller));
}
}
@@ -8525,7 +8569,7 @@
targetUserId).getActiveAdmin();
} else {
ap = getParentOfAdminIfRequired(
- getProfileOwnerOrDeviceOwnerLocked(caller.getUserId()), parent);
+ getProfileOwnerOrDefaultDeviceOwnerLocked(caller.getUserId()), parent);
}
if (ap.disableScreenCapture != disabled) {
@@ -8557,15 +8601,21 @@
}
if (admin != null && admin.disableScreenCapture) {
setScreenCaptureDisabled(UserHandle.USER_ALL);
- } else {
- // Otherwise, update screen capture only for the calling user.
- admin = getProfileOwnerAdminLocked(adminUserId);
- if (admin != null && admin.disableScreenCapture) {
- setScreenCaptureDisabled(adminUserId);
- } else {
- setScreenCaptureDisabled(UserHandle.USER_NULL);
- }
+ return;
}
+ // Otherwise, update screen capture only for the calling user.
+ admin = getProfileOwnerAdminLocked(adminUserId);
+ if (admin != null && admin.disableScreenCapture) {
+ setScreenCaptureDisabled(adminUserId);
+ return;
+ }
+ // If the admin is permission based, update only for the calling user.
+ admin = getUserData(adminUserId).createOrGetPermissionBasedAdmin(adminUserId);
+ if (admin != null && admin.disableScreenCapture) {
+ setScreenCaptureDisabled(adminUserId);
+ return;
+ }
+ setScreenCaptureDisabled(UserHandle.USER_NULL);
}
// Set the latest screen capture policy, overriding any existing ones.
@@ -11424,7 +11474,7 @@
RoleManager.ROLE_DIALER, packageName, 0, UserHandle.of(callerUserId),
AsyncTask.THREAD_POOL_EXECUTOR, callback);
try {
- future.get(5, TimeUnit.SECONDS);
+ future.get(20, TimeUnit.SECONDS);
} catch (TimeoutException e) {
throw new IllegalArgumentException("Timeout when setting the app as the dialer", e);
} catch (ExecutionException e) {
@@ -16466,6 +16516,25 @@
MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
callerPackage,
caller.getUserId());
+ if (SENSOR_PERMISSIONS.contains(permission)
+ && grantState == PERMISSION_GRANT_STATE_GRANTED
+ && (!canAdminGrantSensorsPermissions() || isCallerDelegate(caller))) {
+ if (mInjector.isChangeEnabled(THROW_SECURITY_EXCEPTION_FOR_SENSOR_PERMISSIONS,
+ caller.getPackageName(), caller.getUserId())) {
+ throw new SecurityException(
+ "Caller not permitted to grant sensor permissions.");
+ } else {
+ // This is to match the legacy behaviour.
+ callback.sendResult(Bundle.EMPTY);
+ return;
+ }
+ }
+ // Check all the states where Exceptions aren't thrown but the permission
+ // isn't granted either.
+ if (!canGrantPermission(caller, permission, packageName)) {
+ callback.sendResult(null);
+ return;
+ }
// TODO(b/266924257): decide how to handle the internal state if the package doesn't
// exist, or the permission isn't requested by the app, because we could end up with
// inconsistent state between the policy engine and package manager. Also a package
@@ -16541,6 +16610,41 @@
}
}
+ private static final List<String> SENSOR_PERMISSIONS = new ArrayList<>();
+ {
+ SENSOR_PERMISSIONS.add(Manifest.permission.ACCESS_FINE_LOCATION);
+ SENSOR_PERMISSIONS.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION);
+ SENSOR_PERMISSIONS.add(Manifest.permission.ACCESS_COARSE_LOCATION);
+ SENSOR_PERMISSIONS.add(Manifest.permission.CAMERA);
+ SENSOR_PERMISSIONS.add(Manifest.permission.RECORD_AUDIO);
+ SENSOR_PERMISSIONS.add(Manifest.permission.ACTIVITY_RECOGNITION);
+ SENSOR_PERMISSIONS.add(Manifest.permission.BODY_SENSORS);
+ SENSOR_PERMISSIONS.add(Manifest.permission.BACKGROUND_CAMERA);
+ SENSOR_PERMISSIONS.add(Manifest.permission.RECORD_BACKGROUND_AUDIO);
+ SENSOR_PERMISSIONS.add(Manifest.permission.BODY_SENSORS_BACKGROUND);
+ SENSOR_PERMISSIONS.add(
+ Manifest.permission.BODY_SENSORS_WRIST_TEMPERATURE);
+ SENSOR_PERMISSIONS.add(
+ Manifest.permission.BODY_SENSORS_WRIST_TEMPERATURE_BACKGROUND);
+ }
+
+ private boolean canGrantPermission(CallerIdentity caller, String permission,
+ String targetPackageName) {
+ boolean isPostQAdmin = getTargetSdk(caller.getPackageName(), caller.getUserId())
+ >= android.os.Build.VERSION_CODES.Q;
+ if (!isPostQAdmin) {
+ // Legacy admins assume that they cannot control pre-M apps
+ if (getTargetSdk(targetPackageName, caller.getUserId())
+ < android.os.Build.VERSION_CODES.M) {
+ return false;
+ }
+ }
+ if (!isRuntimePermission(permission)) {
+ return false;
+ }
+ return true;
+ }
+
private void enforcePermissionGrantStateOnFinancedDevice(
String packageName, String permission) {
if (!Manifest.permission.READ_PHONE_STATE.equals(permission)) {
@@ -17637,7 +17741,6 @@
synchronized (getLockObject()) {
if (isPermissionCheckFlagEnabled()) {
- // TODO: add support for DELEGATION_SECURITY_LOGGING
enforcePermission(MANAGE_DEVICE_POLICY_SECURITY_LOGGING, caller.getPackageName(),
UserHandle.USER_ALL);
} else {
@@ -17718,7 +17821,8 @@
final CallerIdentity caller = getCallerIdentity(admin, packageName);
if (isPermissionCheckFlagEnabled()) {
- // TODO: Restore the "affiliated users" check
+ Preconditions.checkCallAuthorization(isOrganizationOwnedDeviceWithManagedProfile()
+ || areAllUsersAffiliatedWithDeviceLocked());
enforcePermission(MANAGE_DEVICE_POLICY_SECURITY_LOGGING, caller.getPackageName(),
UserHandle.USER_ALL);
} else {
@@ -17770,7 +17874,9 @@
final CallerIdentity caller = getCallerIdentity(admin, packageName);
if (isPermissionCheckFlagEnabled()) {
- // TODO: Restore the "affiliated users" check
+ Preconditions.checkCallAuthorization(isOrganizationOwnedDeviceWithManagedProfile()
+ || areAllUsersAffiliatedWithDeviceLocked());
+
enforcePermission(MANAGE_DEVICE_POLICY_SECURITY_LOGGING, caller.getPackageName(),
UserHandle.USER_ALL);
} else {
@@ -22321,244 +22427,208 @@
// Permissions of existing DPC types.
private static final List<String> DEFAULT_DEVICE_OWNER_PERMISSIONS = List.of(
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL,
+ MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT,
MANAGE_DEVICE_POLICY_ACROSS_USERS,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL,
MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL,
- SET_TIME,
- SET_TIME_ZONE,
- MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
- MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
- MANAGE_DEVICE_POLICY_WIFI,
- MANAGE_DEVICE_POLICY_WIPE_DATA,
- MANAGE_DEVICE_POLICY_SCREEN_CAPTURE,
- MANAGE_DEVICE_POLICY_SYSTEM_UPDATES,
- MANAGE_DEVICE_POLICY_SECURITY_LOGGING,
- MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING,
- MANAGE_DEVICE_POLICY_MTE,
- MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS,
- MANAGE_DEVICE_POLICY_PACKAGE_STATE,
- MANAGE_DEVICE_POLICY_LOCK,
- MANAGE_DEVICE_POLICY_FACTORY_RESET,
- MANAGE_DEVICE_POLICY_KEYGUARD,
- MANAGE_DEVICE_POLICY_CERTIFICATES,
- MANAGE_DEVICE_POLICY_KEYGUARD,
- MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
- MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE,
- MANAGE_DEVICE_POLICY_APPS_CONTROL,
- MANAGE_DEVICE_POLICY_LOCK_TASK,
- MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT,
- MANAGE_DEVICE_POLICY_CAMERA,
- MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE,
- MANAGE_DEVICE_POLICY_DEFAULT_SMS,
- MANAGE_DEVICE_POLICY_PACKAGE_STATE,
- MANAGE_DEVICE_POLICY_PROFILE_INTERACTION,
- MANAGE_DEVICE_POLICY_RESET_PASSWORD,
- MANAGE_DEVICE_POLICY_STATUS_BAR,
- MANAGE_DEVICE_POLICY_LOCK_TASK,
- MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT,
MANAGE_DEVICE_POLICY_AIRPLANE_MODE,
+ MANAGE_DEVICE_POLICY_APPS_CONTROL,
+ MANAGE_DEVICE_POLICY_APP_RESTRICTIONS,
MANAGE_DEVICE_POLICY_AUDIO_OUTPUT,
MANAGE_DEVICE_POLICY_AUTOFILL,
MANAGE_DEVICE_POLICY_BLUETOOTH,
MANAGE_DEVICE_POLICY_CALLS,
MANAGE_DEVICE_POLICY_CAMERA,
+ MANAGE_DEVICE_POLICY_CERTIFICATES,
+ MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE,
MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES,
+ MANAGE_DEVICE_POLICY_DEFAULT_SMS,
MANAGE_DEVICE_POLICY_DISPLAY,
MANAGE_DEVICE_POLICY_FACTORY_RESET,
MANAGE_DEVICE_POLICY_FUN,
MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES,
+ MANAGE_DEVICE_POLICY_KEYGUARD,
MANAGE_DEVICE_POLICY_LOCALE,
MANAGE_DEVICE_POLICY_LOCATION,
+ MANAGE_DEVICE_POLICY_LOCK,
MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS,
+ MANAGE_DEVICE_POLICY_LOCK_TASK,
MANAGE_DEVICE_POLICY_MICROPHONE,
MANAGE_DEVICE_POLICY_MOBILE_NETWORK,
+ MANAGE_DEVICE_POLICY_MTE,
MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION,
+ MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
+ MANAGE_DEVICE_POLICY_PACKAGE_STATE,
MANAGE_DEVICE_POLICY_PHYSICAL_MEDIA,
MANAGE_DEVICE_POLICY_PRINTING,
- MANAGE_DEVICE_POLICY_RESTRICT_PRIVATE_DNS,
MANAGE_DEVICE_POLICY_PROFILES,
MANAGE_DEVICE_POLICY_PROFILE_INTERACTION,
+ MANAGE_DEVICE_POLICY_RESET_PASSWORD,
+ MANAGE_DEVICE_POLICY_RESTRICT_PRIVATE_DNS,
+ MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
MANAGE_DEVICE_POLICY_SAFE_BOOT,
+ MANAGE_DEVICE_POLICY_SCREEN_CAPTURE,
MANAGE_DEVICE_POLICY_SCREEN_CONTENT,
+ MANAGE_DEVICE_POLICY_SECURITY_LOGGING,
MANAGE_DEVICE_POLICY_SMS,
+ MANAGE_DEVICE_POLICY_STATUS_BAR,
+ MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE,
MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS,
+ MANAGE_DEVICE_POLICY_SYSTEM_UPDATES,
MANAGE_DEVICE_POLICY_TIME,
+ MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING,
MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER,
MANAGE_DEVICE_POLICY_USERS,
MANAGE_DEVICE_POLICY_VPN,
MANAGE_DEVICE_POLICY_WALLPAPER,
MANAGE_DEVICE_POLICY_WIFI,
MANAGE_DEVICE_POLICY_WINDOWS,
- MANAGE_DEVICE_POLICY_APP_RESTRICTIONS
+ MANAGE_DEVICE_POLICY_WIPE_DATA,
+ SET_TIME,
+ SET_TIME_ZONE
);
private static final List<String> FINANCED_DEVICE_OWNER_PERMISSIONS = List.of(
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL,
MANAGE_DEVICE_POLICY_ACROSS_USERS,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL,
MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL,
- MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
- MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
- MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
- MANAGE_DEVICE_POLICY_FACTORY_RESET,
- MANAGE_DEVICE_POLICY_KEYGUARD,
- MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
- MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE,
MANAGE_DEVICE_POLICY_APPS_CONTROL,
- MANAGE_DEVICE_POLICY_LOCK_TASK,
MANAGE_DEVICE_POLICY_CALLS,
MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES,
+ MANAGE_DEVICE_POLICY_FACTORY_RESET,
MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES,
- MANAGE_DEVICE_POLICY_USERS,
+ MANAGE_DEVICE_POLICY_KEYGUARD,
+ MANAGE_DEVICE_POLICY_LOCK_TASK,
+ MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
+ MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
MANAGE_DEVICE_POLICY_SAFE_BOOT,
+ MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE,
MANAGE_DEVICE_POLICY_TIME,
- MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS);
- private static final List<String> PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE_PERMISSIONS =
+ MANAGE_DEVICE_POLICY_USERS,
+ MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS
+ );
+
+ /**
+ * All the permisisons granted to a profile owner.
+ */
+ private static final List<String> PROFILE_OWNER_PERMISSIONS =
List.of(
- MANAGE_DEVICE_POLICY_ACROSS_USERS,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL,
- SET_TIME,
- SET_TIME_ZONE,
- MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
- MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
- MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE,
- MANAGE_DEVICE_POLICY_APPS_CONTROL,
- MANAGE_DEVICE_POLICY_WIFI,
- MANAGE_DEVICE_POLICY_WIPE_DATA,
- MANAGE_DEVICE_POLICY_SCREEN_CAPTURE,
- MANAGE_DEVICE_POLICY_SYSTEM_UPDATES,
- MANAGE_DEVICE_POLICY_SECURITY_LOGGING,
- MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING,
- MANAGE_DEVICE_POLICY_MTE,
- MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS,
- MANAGE_DEVICE_POLICY_PACKAGE_STATE,
- MANAGE_DEVICE_POLICY_LOCK,
- MANAGE_DEVICE_POLICY_FACTORY_RESET,
- MANAGE_DEVICE_POLICY_KEYGUARD,
- MANAGE_DEVICE_POLICY_AIRPLANE_MODE,
MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL,
+ MANAGE_DEVICE_POLICY_APPS_CONTROL,
+ MANAGE_DEVICE_POLICY_APP_RESTRICTIONS,
MANAGE_DEVICE_POLICY_AUDIO_OUTPUT,
MANAGE_DEVICE_POLICY_AUTOFILL,
- MANAGE_DEVICE_POLICY_BLUETOOTH,
MANAGE_DEVICE_POLICY_CALLS,
- MANAGE_DEVICE_POLICY_CAMERA,
MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES,
MANAGE_DEVICE_POLICY_DISPLAY,
MANAGE_DEVICE_POLICY_FACTORY_RESET,
MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES,
+ MANAGE_DEVICE_POLICY_KEYGUARD,
MANAGE_DEVICE_POLICY_LOCALE,
MANAGE_DEVICE_POLICY_LOCATION,
+ MANAGE_DEVICE_POLICY_LOCK,
MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS,
- MANAGE_DEVICE_POLICY_MICROPHONE,
- MANAGE_DEVICE_POLICY_MOBILE_NETWORK,
MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION,
- MANAGE_DEVICE_POLICY_PHYSICAL_MEDIA,
+ MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
+ MANAGE_DEVICE_POLICY_PACKAGE_STATE,
MANAGE_DEVICE_POLICY_PRINTING,
MANAGE_DEVICE_POLICY_PROFILES,
MANAGE_DEVICE_POLICY_PROFILE_INTERACTION,
- MANAGE_DEVICE_POLICY_RESTRICT_PRIVATE_DNS,
- MANAGE_DEVICE_POLICY_SAFE_BOOT,
+ MANAGE_DEVICE_POLICY_RESET_PASSWORD,
+ MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
+ MANAGE_DEVICE_POLICY_SCREEN_CAPTURE,
MANAGE_DEVICE_POLICY_SCREEN_CONTENT,
- MANAGE_DEVICE_POLICY_SMS,
+ MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE,
MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS,
MANAGE_DEVICE_POLICY_TIME,
MANAGE_DEVICE_POLICY_VPN,
- MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER,
- MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE,
- MANAGE_DEVICE_POLICY_DEFAULT_SMS,
- MANAGE_DEVICE_POLICY_PACKAGE_STATE,
- MANAGE_DEVICE_POLICY_RESET_PASSWORD,
- MANAGE_DEVICE_POLICY_APP_RESTRICTIONS,
- MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER,
- MANAGE_DEVICE_POLICY_KEYGUARD,
- MANAGE_DEVICE_POLICY_WIFI,
- MANAGE_DEVICE_POLICY_WIPE_DATA,
- MANAGE_DEVICE_POLICY_SCREEN_CAPTURE,
- MANAGE_DEVICE_POLICY_SYSTEM_UPDATES,
- MANAGE_DEVICE_POLICY_SECURITY_LOGGING,
- MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING,
- MANAGE_DEVICE_POLICY_MTE,
- MANAGE_DEVICE_POLICY_PACKAGE_STATE,
- MANAGE_DEVICE_POLICY_LOCK,
- MANAGE_DEVICE_POLICY_FACTORY_RESET,
- MANAGE_DEVICE_POLICY_KEYGUARD,
- MANAGE_DEVICE_POLICY_CERTIFICATES);
- private static final List<String> PROFILE_OWNER_ON_USER_0_PERMISSIONS = List.of(
- SET_TIME,
- SET_TIME_ZONE,
- MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
- MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE,
- MANAGE_DEVICE_POLICY_APPS_CONTROL,
- MANAGE_DEVICE_POLICY_LOCK_TASK,
- MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
- MANAGE_DEVICE_POLICY_WIPE_DATA,
- MANAGE_DEVICE_POLICY_SCREEN_CAPTURE,
- MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS,
- MANAGE_DEVICE_POLICY_PACKAGE_STATE,
- MANAGE_DEVICE_POLICY_LOCK,
- MANAGE_DEVICE_POLICY_KEYGUARD,
- MANAGE_DEVICE_POLICY_LOCK_TASK,
- MANAGE_DEVICE_POLICY_AIRPLANE_MODE,
- MANAGE_DEVICE_POLICY_BLUETOOTH,
- MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES,
- MANAGE_DEVICE_POLICY_FACTORY_RESET,
- MANAGE_DEVICE_POLICY_FUN,
- MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES,
- MANAGE_DEVICE_POLICY_MOBILE_NETWORK,
- MANAGE_DEVICE_POLICY_USERS,
- MANAGE_DEVICE_POLICY_PHYSICAL_MEDIA,
- MANAGE_DEVICE_POLICY_SAFE_BOOT,
- MANAGE_DEVICE_POLICY_SMS,
- MANAGE_DEVICE_POLICY_TIME,
- MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER,
- MANAGE_DEVICE_POLICY_WINDOWS,
- MANAGE_DEVICE_POLICY_LOCK_TASK,
- MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT,
- MANAGE_DEVICE_POLICY_CAMERA,
- MANAGE_DEVICE_POLICY_PACKAGE_STATE,
- MANAGE_DEVICE_POLICY_RESET_PASSWORD,
- MANAGE_DEVICE_POLICY_STATUS_BAR,
- MANAGE_DEVICE_POLICY_APP_RESTRICTIONS,
- MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS);
- private static final List<String> PROFILE_OWNER_PERMISSIONS = List.of(
- MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL,
- MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
- MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
- MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE,
- MANAGE_DEVICE_POLICY_APPS_CONTROL,
- MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
- MANAGE_DEVICE_POLICY_WIPE_DATA,
- MANAGE_DEVICE_POLICY_SCREEN_CAPTURE,
- MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS,
- MANAGE_DEVICE_POLICY_PACKAGE_STATE,
- MANAGE_DEVICE_POLICY_LOCK,
- MANAGE_DEVICE_POLICY_KEYGUARD,
- MANAGE_DEVICE_POLICY_APPS_CONTROL,
- MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT,
- MANAGE_DEVICE_POLICY_AUDIO_OUTPUT,
- MANAGE_DEVICE_POLICY_AUTOFILL,
- MANAGE_DEVICE_POLICY_CALLS,
- MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES,
- MANAGE_DEVICE_POLICY_DISPLAY,
- MANAGE_DEVICE_POLICY_FACTORY_RESET,
- MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES,
- MANAGE_DEVICE_POLICY_LOCALE,
- MANAGE_DEVICE_POLICY_LOCATION,
- MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS,
- MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION,
- MANAGE_DEVICE_POLICY_PRINTING,
- MANAGE_DEVICE_POLICY_PROFILES,
- MANAGE_DEVICE_POLICY_PROFILE_INTERACTION,
- MANAGE_DEVICE_POLICY_SCREEN_CONTENT,
- MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS,
- MANAGE_DEVICE_POLICY_TIME,
- MANAGE_DEVICE_POLICY_VPN,
- MANAGE_DEVICE_POLICY_PACKAGE_STATE,
- MANAGE_DEVICE_POLICY_PROFILE_INTERACTION,
- MANAGE_DEVICE_POLICY_RESET_PASSWORD,
- MANAGE_DEVICE_POLICY_APP_RESTRICTIONS
+ MANAGE_DEVICE_POLICY_WIPE_DATA
);
+ /**
+ * All the additional permissions granted to an organisation owned profile owner.
+ */
+ private static final List<String>
+ ADDITIONAL_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE_PERMISSIONS =
+ List.of(
+ MANAGE_DEVICE_POLICY_ACROSS_USERS,
+ MANAGE_DEVICE_POLICY_AIRPLANE_MODE,
+ MANAGE_DEVICE_POLICY_APPS_CONTROL,
+ MANAGE_DEVICE_POLICY_BLUETOOTH,
+ MANAGE_DEVICE_POLICY_CAMERA,
+ MANAGE_DEVICE_POLICY_CERTIFICATES,
+ MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE,
+ MANAGE_DEVICE_POLICY_DEFAULT_SMS,
+ MANAGE_DEVICE_POLICY_LOCALE,
+ MANAGE_DEVICE_POLICY_MICROPHONE,
+ MANAGE_DEVICE_POLICY_MOBILE_NETWORK,
+ MANAGE_DEVICE_POLICY_MTE,
+ MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION,
+ MANAGE_DEVICE_POLICY_PHYSICAL_MEDIA,
+ MANAGE_DEVICE_POLICY_RESTRICT_PRIVATE_DNS,
+ MANAGE_DEVICE_POLICY_SAFE_BOOT,
+ MANAGE_DEVICE_POLICY_SECURITY_LOGGING,
+ MANAGE_DEVICE_POLICY_SMS,
+ MANAGE_DEVICE_POLICY_SYSTEM_UPDATES,
+ MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING,
+ MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER,
+ MANAGE_DEVICE_POLICY_WIFI,
+ SET_TIME,
+ SET_TIME_ZONE
+ );
+
+
+ private static final List<String> ADDITIONAL_PROFILE_OWNER_ON_USER_0_PERMISSIONS =
+ List.of(
+ MANAGE_DEVICE_POLICY_AIRPLANE_MODE,
+ MANAGE_DEVICE_POLICY_BLUETOOTH,
+ MANAGE_DEVICE_POLICY_CAMERA,
+ MANAGE_DEVICE_POLICY_DISPLAY,
+ MANAGE_DEVICE_POLICY_FUN,
+ MANAGE_DEVICE_POLICY_LOCK_TASK,
+ MANAGE_DEVICE_POLICY_MOBILE_NETWORK,
+ MANAGE_DEVICE_POLICY_PHYSICAL_MEDIA,
+ MANAGE_DEVICE_POLICY_PRINTING,
+ MANAGE_DEVICE_POLICY_PROFILES,
+ MANAGE_DEVICE_POLICY_PROFILE_INTERACTION,
+ MANAGE_DEVICE_POLICY_SAFE_BOOT,
+ MANAGE_DEVICE_POLICY_SMS,
+ MANAGE_DEVICE_POLICY_STATUS_BAR,
+ MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS,
+ MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER,
+ MANAGE_DEVICE_POLICY_USERS,
+ MANAGE_DEVICE_POLICY_WINDOWS,
+ SET_TIME,
+ SET_TIME_ZONE
+ );
+
+ /**
+ * Combination of {@link PROFILE_OWNER_PERMISSIONS} and
+ * {@link ADDITIONAL_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE_PERMISSIONS}.
+ */
+ private static final List<String> PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE_PERMISSIONS =
+ new ArrayList();
+
+ /**
+ * Combination of {@link PROFILE_OWNER_PERMISSIONS} and
+ * {@link ADDITIONAL_PROFILE_OWNER_ON_USER_0_PERMISSIONS}.
+ */
+ private static final List<String> PROFILE_OWNER_ON_USER_0_PERMISSIONS =
+ new ArrayList();
+
+
private static final HashMap<Integer, List<String>> DPC_PERMISSIONS = new HashMap<>();
{
+ // Organisation owned profile owners have all the permission of a profile owner plus
+ // some extra permissions.
+ PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE_PERMISSIONS.addAll(PROFILE_OWNER_PERMISSIONS);
+ PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE_PERMISSIONS.addAll(
+ ADDITIONAL_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE_PERMISSIONS);
+ // Profile owners on user 0 have all the permission of a profile owner plus
+ // some extra permissions.
+ PROFILE_OWNER_ON_USER_0_PERMISSIONS.addAll(PROFILE_OWNER_PERMISSIONS);
+ PROFILE_OWNER_ON_USER_0_PERMISSIONS.addAll(ADDITIONAL_PROFILE_OWNER_ON_USER_0_PERMISSIONS);
+
DPC_PERMISSIONS.put(DEFAULT_DEVICE_OWNER, DEFAULT_DEVICE_OWNER_PERMISSIONS);
DPC_PERMISSIONS.put(FINANCED_DEVICE_OWNER, FINANCED_DEVICE_OWNER_PERMISSIONS);
DPC_PERMISSIONS.put(PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE,
@@ -22566,14 +22636,6 @@
DPC_PERMISSIONS.put(PROFILE_OWNER_ON_USER_0, PROFILE_OWNER_ON_USER_0_PERMISSIONS);
DPC_PERMISSIONS.put(PROFILE_OWNER, PROFILE_OWNER_PERMISSIONS);
}
-
- // Map of permission Active admin DEVICE_POLICY.
- //TODO(b/254253251) Fill this map in as new permissions are added for policies.
- private static final HashMap<String, Integer> ACTIVE_ADMIN_POLICIES = new HashMap<>();
- {
- //Any ActiveAdmin is able to call the support message APIs without certain policies.
- ACTIVE_ADMIN_POLICIES.put(MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE, null);
- }
//Map of Permission to Delegate Scope.
private static final HashMap<String, String> DELEGATE_SCOPES = new HashMap<>();
{
@@ -22587,75 +22649,40 @@
private static final HashMap<String, String> CROSS_USER_PERMISSIONS =
new HashMap<>();
{
- // Time and Timezone is intrinsically global so there is no cross-user permission.
+ // The permissions are all intrinsically global and therefore have no cross-user permission.
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_FACTORY_RESET, null);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_MTE, null);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SECURITY_LOGGING, null);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_STATUS_BAR, null);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SYSTEM_UPDATES, null);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING, null);
CROSS_USER_PERMISSIONS.put(SET_TIME, null);
CROSS_USER_PERMISSIONS.put(SET_TIME_ZONE, null);
- // system updates are intrinsically global so there is no cross-user permission
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SYSTEM_UPDATES, null);
- // security logs are intrinsically global so there is no cross-user permission
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SECURITY_LOGGING, null);
- // usb signalling is intrinsically global so there is no cross-user permission
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING, null);
- // mte is intrinsically global so there is no cross-user permission
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_MTE, null);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_FACTORY_RESET, null);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_STATUS_BAR, null);
- // Organisation identity policy will involve data of other organisations on the device and
- // therefore the FULL cross-user permission is required.
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_WIFI,
- MANAGE_DEVICE_POLICY_ACROSS_USERS);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_WIPE_DATA,
- MANAGE_DEVICE_POLICY_ACROSS_USERS);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SCREEN_CAPTURE,
- MANAGE_DEVICE_POLICY_ACROSS_USERS);
+
+ // The permissions are all critical for securing data within the current user and
+ // therefore are protected with MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL for
+ // cross-user calls.
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_KEYGUARD,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS,
MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_PACKAGE_STATE,
- MANAGE_DEVICE_POLICY_ACROSS_USERS);
- CROSS_USER_PERMISSIONS.put(
- MANAGE_DEVICE_POLICY_LOCK, MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(
- MANAGE_DEVICE_POLICY_KEYGUARD, MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL);
- // Granting runtime permissions can grant applications significant powers therefore the FULL
- // cross-user permission is required.
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_APPS_CONTROL,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_LOCK_TASK,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+
+ // These permissions are required for securing device ownership without accessing user data
+ // and therefore are protected with MANAGE_DEVICE_POLICY_ACROSS_USERS for cross-user calls.
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_ACCOUNT_MANAGEMENT,
MANAGE_DEVICE_POLICY_ACROSS_USERS);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_AIRPLANE_MODE,
MANAGE_DEVICE_POLICY_ACROSS_USERS);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_AUDIO_OUTPUT,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_AUTOFILL,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_BLUETOOTH,
MANAGE_DEVICE_POLICY_ACROSS_USERS);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_CALLS,
MANAGE_DEVICE_POLICY_ACROSS_USERS);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_CAMERA,
MANAGE_DEVICE_POLICY_ACROSS_USERS);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_DISPLAY,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_FACTORY_RESET,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_FUN,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_INSTALL_UNKNOWN_SOURCES,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_SECURITY_CRITICAL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_LOCALE,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_LOCATION,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_DEFAULT_SMS,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_MICROPHONE,
MANAGE_DEVICE_POLICY_ACROSS_USERS);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_MOBILE_NETWORK,
@@ -22664,46 +22691,77 @@
MANAGE_DEVICE_POLICY_ACROSS_USERS);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_PHYSICAL_MEDIA,
MANAGE_DEVICE_POLICY_ACROSS_USERS);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_PRINTING,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_PACKAGE_STATE,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_RESTRICT_PRIVATE_DNS,
MANAGE_DEVICE_POLICY_ACROSS_USERS);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_PROFILES,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_PROFILE_INTERACTION,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SAFE_BOOT,
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SCREEN_CAPTURE,
MANAGE_DEVICE_POLICY_ACROSS_USERS);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SCREEN_CONTENT,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SMS,
MANAGE_DEVICE_POLICY_ACROSS_USERS);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SAFE_BOOT,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_TIME,
MANAGE_DEVICE_POLICY_ACROSS_USERS);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER,
MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_WIFI,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_WIPE_DATA,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS);
+
+ // These permissions may grant access to user data and therefore must be protected with
+ // MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL for cross-user calls.
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_APPS_CONTROL,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_APP_RESTRICTIONS,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_AUDIO_OUTPUT,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_AUTOFILL,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_DISPLAY,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_FUN,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_LOCALE,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_LOCATION,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_LOCK,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_LOCK_TASK,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_PROFILES,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_PROFILE_INTERACTION,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_PRINTING,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_RESET_PASSWORD,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SCREEN_CONTENT,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
+ CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS,
+ MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_USERS,
MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_VPN,
MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_WALLPAPER,
MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_WIFI,
- MANAGE_DEVICE_POLICY_ACROSS_USERS);
CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_WINDOWS,
MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_APP_RESTRICTIONS,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_DEFAULT_SMS,
- MANAGE_DEVICE_POLICY_ACROSS_USERS);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_PACKAGE_STATE,
- MANAGE_DEVICE_POLICY_ACROSS_USERS);
- CROSS_USER_PERMISSIONS.put(MANAGE_DEVICE_POLICY_RESET_PASSWORD,
- MANAGE_DEVICE_POLICY_ACROSS_USERS_FULL);
}
/**
@@ -22727,6 +22785,26 @@
}
/**
+ * Checks if the calling process has been granted permission to apply a device policy on a
+ * specific user.
+ * The given permission will be checked along with its associated cross-user permission if it
+ * exists and the target user is different to the calling user.
+ * Returns an {@link EnforcingAdmin} for the caller.
+ *
+ * @param admin the component name of the admin.
+ * @param callerPackageName The package name of the calling application.
+ * @param permission The name of the permission being checked.
+ * @param deviceAdminPolicy The userId of the user which the caller needs permission to act on.
+ * @throws SecurityException if the caller has not been granted the given permission,
+ * the associated cross-user permission if the caller's user is different to the target user.
+ */
+ private EnforcingAdmin enforcePermissionAndGetEnforcingAdmin(@Nullable ComponentName admin,
+ String permission, int deviceAdminPolicy, String callerPackageName, int targetUserId) {
+ enforcePermission(permission, deviceAdminPolicy, callerPackageName, targetUserId);
+ return getEnforcingAdminForCaller(admin, callerPackageName);
+ }
+
+ /**
* Checks whether the calling process has been granted permission to query a device policy on
* a specific user.
* The given permission will be checked along with its associated cross-user permission if it
@@ -22748,6 +22826,9 @@
POLICY_IDENTIFIER_TO_PERMISSION.put(AUTO_TIMEZONE_POLICY, SET_TIME_ZONE);
}
+ private static final HashMap<String, Integer> POLICY_IDENTIFIER_TO_ACTIVE_ADMIN_POLICY =
+ new HashMap<>();
+
/**
* Checks if the calling process has been granted permission to apply a device policy on a
* specific user.
@@ -22763,6 +22844,36 @@
private void enforcePermission(String permission, String callerPackageName, int targetUserId)
throws SecurityException {
if (!hasPermission(permission, callerPackageName, targetUserId)) {
+ // TODO(b/276920002): Split the error messages so that the cross-user permission
+ // is only mentioned when it is needed.
+ throw new SecurityException("Caller does not have the required permissions for "
+ + "this user. Permissions required: {"
+ + permission
+ + ", "
+ + CROSS_USER_PERMISSIONS.get(permission)
+ + "(if calling cross-user)"
+ + "}");
+ }
+ }
+
+ /**
+ * Checks if the calling process has been granted permission to apply a device policy on a
+ * specific user.
+ * The given permission will be checked along with its associated cross-user permission if it
+ * exists and the target user is different to the calling user.
+ *
+ * @param callerPackageName The package name of the calling application.
+ * @param permission The name of the permission being checked.
+ * @param targetUserId The userId of the user which the caller needs permission to act on.
+ * @throws SecurityException if the caller has not been granted the given permission,
+ * the associated cross-user permission if the caller's user is different to the target user.
+ */
+ private void enforcePermission(String permission, int adminPolicy,
+ String callerPackageName, int targetUserId)
+ throws SecurityException {
+ if (!hasPermissionOrAdminPolicy(permission, callerPackageName, adminPolicy, targetUserId)) {
+ // TODO(b/276920002): Split the error messages so that the cross-user permission
+ // is only mentioned when it is needed.
throw new SecurityException("Caller does not have the required permissions for "
+ "this user. Permissions required: {"
+ permission
@@ -22804,16 +22915,26 @@
*/
private boolean hasPermission(String permission, String callerPackageName, int targetUserId) {
CallerIdentity caller = getCallerIdentity(callerPackageName);
- boolean hasPermissionOnOwnUser = hasPermission(permission, callerPackageName);
+ boolean hasPermissionOnOwnUser = hasPermission(permission, caller.getPackageName());
boolean hasPermissionOnTargetUser = true;
if (hasPermissionOnOwnUser & caller.getUserId() != targetUserId) {
hasPermissionOnTargetUser = hasPermission(CROSS_USER_PERMISSIONS.get(permission),
- callerPackageName);
+ caller.getPackageName());
}
return hasPermissionOnOwnUser && hasPermissionOnTargetUser;
}
+ private boolean hasPermissionOrAdminPolicy(String permission, String callerPackageName,
+ int adminPolicy, int targetUserId) {
+ CallerIdentity caller = getCallerIdentity(callerPackageName);
+ if (hasPermission(permission, caller.getPackageName(), targetUserId)) {
+ return true;
+ }
+ ActiveAdmin deviceAdmin = getActiveAdminForCaller(null, caller);
+ return deviceAdmin != null && deviceAdmin.info.usesPolicy(adminPolicy);
+ }
+
/**
* Return whether the calling process has been granted the given permission.
*
@@ -22856,23 +22977,6 @@
if (DELEGATE_SCOPES.containsKey(permission)) {
return isCallerDelegate(caller, DELEGATE_SCOPES.get(permission));
}
- // Check if the caller is an active admin that uses a certain policy.
- if (ACTIVE_ADMIN_POLICIES.containsKey(permission)) {
- try {
- if (ACTIVE_ADMIN_POLICIES.get(permission) != null) {
- return getActiveAdminForCallerLocked(
- null, ACTIVE_ADMIN_POLICIES.get(permission), false) != null;
- } else {
- // If the permission maps to no policy (null) this means that any active admin
- // has permission.
- return isCallerActiveAdminOrDelegate(caller, null);
- }
- } catch (SecurityException e) {
- // A security exception means there is not an active admin with permission and
- // therefore
- return false;
- }
- }
return false;
}
@@ -22925,9 +23029,7 @@
if (admin != null) {
return EnforcingAdmin.createDeviceAdminEnforcingAdmin(who, userId, admin);
}
- if (admin == null) {
- admin = getUserData(userId).createOrGetPermissionBasedAdmin(userId);
- }
+ admin = getUserData(userId).createOrGetPermissionBasedAdmin(userId);
return EnforcingAdmin.createEnforcingAdmin(caller.getPackageName(), userId, admin);
}
@@ -23476,15 +23578,13 @@
// We need to add a mapping of policyId to permission in POLICY_IDENTIFIER_TO_PERMISSION
// for each migrated permission.
private List<ActiveAdmin> getNonDPCActiveAdminsForPolicyLocked(String policyIdentifier) {
- String permission = POLICY_IDENTIFIER_TO_PERMISSION.get(policyIdentifier);
- if (permission == null) {
- Slogf.e(LOG_TAG, "Can't find a permission for %s in POLICY_IDENTIFIER_TO_PERMISSION",
+ Integer activeAdminPolicy = POLICY_IDENTIFIER_TO_ACTIVE_ADMIN_POLICY.get(policyIdentifier);
+ if (activeAdminPolicy == null) {
+ Slogf.e(LOG_TAG,
+ "Can't find a active admin policy for %s in POLICY_IDENTIFIER_TO_PERMISSION",
policyIdentifier);
return new ArrayList<>();
}
- if (!ACTIVE_ADMIN_POLICIES.containsKey(permission)) {
- return new ArrayList<>();
- }
List<ActiveAdmin> admins = new ArrayList<>();
for (UserInfo userInfo : mUserManager.getUsers()) {
@@ -23495,7 +23595,7 @@
}
DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
if (isActiveAdminWithPolicyForUserLocked(
- policy.mAdminMap.get(admin), ACTIVE_ADMIN_POLICIES.get(permission),
+ policy.mAdminMap.get(admin), activeAdminPolicy,
userInfo.id)) {
admins.add(policy.mAdminMap.get(admin));
}
diff --git a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
index fc25152..3bef413 100644
--- a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
@@ -126,7 +126,7 @@
return mClock::now;
}
- }, // pass in test looper instead, pass in offsetable clock
+ }, // pass in test looper instead, pass in offsettable clock
() -> { }, mTestLooper.getLooper(), mSensorManager, lightSensor,
mBrightnessMappingStrategy, LIGHT_SENSOR_WARMUP_TIME, BRIGHTNESS_MIN_FLOAT,
BRIGHTNESS_MAX_FLOAT, DOZE_SCALE_FACTOR, LIGHT_SENSOR_RATE,
@@ -300,6 +300,179 @@
}
@Test
+ public void testShortTermModelTimesOut() throws Exception {
+ ArgumentCaptor<SensorEventListener> listenerCaptor =
+ ArgumentCaptor.forClass(SensorEventListener.class);
+ verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor),
+ eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class));
+ SensorEventListener listener = listenerCaptor.getValue();
+
+ // Sensor reads 123 lux,
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 123));
+ // User sets brightness to 100
+ mController.configure(AUTO_BRIGHTNESS_ENABLED, /* configuration= */ null,
+ /* brightness= */ 0.5f, /* userChangedBrightness= */ true, /* adjustment= */ 0,
+ /* userChanged= */ false, DisplayPowerRequest.POLICY_BRIGHT,
+ /* shouldResetShortTermModel= */ true);
+
+ when(mBrightnessMappingStrategy.getShortTermModelTimeout()).thenReturn(2000L);
+
+ mController.switchToIdleMode();
+ when(mIdleBrightnessMappingStrategy.isForIdleMode()).thenReturn(true);
+ when(mBrightnessMappingStrategy.shouldResetShortTermModel(
+ 123f, 0.5f)).thenReturn(true);
+
+ // Sensor reads 1000 lux,
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1000));
+ mTestLooper.moveTimeForward(
+ mBrightnessMappingStrategy.getShortTermModelTimeout() + 1000);
+ mTestLooper.dispatchAll();
+
+ mController.switchToInteractiveScreenBrightnessMode();
+ mTestLooper.moveTimeForward(4000);
+ mTestLooper.dispatchAll();
+
+ // Verify only happens on the first configure. (i.e. not again when switching back)
+ // Intentionally using any() to ensure it's not called whatsoever.
+ verify(mBrightnessMappingStrategy, times(1))
+ .addUserDataPoint(123.0f, 0.5f);
+ verify(mBrightnessMappingStrategy, times(1))
+ .addUserDataPoint(anyFloat(), anyFloat());
+ }
+
+ @Test
+ public void testShortTermModelDoesntTimeOut() throws Exception {
+ ArgumentCaptor<SensorEventListener> listenerCaptor =
+ ArgumentCaptor.forClass(SensorEventListener.class);
+ verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor),
+ eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class));
+ SensorEventListener listener = listenerCaptor.getValue();
+
+ // Sensor reads 123 lux,
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 123));
+ // User sets brightness to 100
+ mController.configure(AUTO_BRIGHTNESS_ENABLED, null /* configuration= */,
+ 0.51f /* brightness= */, true /* userChangedBrightness= */, 0 /* adjustment= */,
+ false /* userChanged= */, DisplayPowerRequest.POLICY_BRIGHT,
+ /* shouldResetShortTermModel= */ true);
+
+ when(mBrightnessMappingStrategy.shouldResetShortTermModel(
+ anyFloat(), anyFloat())).thenReturn(true);
+ when(mBrightnessMappingStrategy.getShortTermModelTimeout()).thenReturn(2000L);
+ when(mBrightnessMappingStrategy.getUserBrightness()).thenReturn(0.51f);
+ when(mBrightnessMappingStrategy.getUserLux()).thenReturn(123.0f);
+
+ mController.switchToIdleMode();
+ when(mIdleBrightnessMappingStrategy.isForIdleMode()).thenReturn(true);
+
+ // Time does not move forward, since clock is doesn't increment naturally.
+ mTestLooper.dispatchAll();
+
+ // Sensor reads 100000 lux,
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 678910));
+ mController.switchToInteractiveScreenBrightnessMode();
+
+ // Verify short term model is not reset.
+ verify(mBrightnessMappingStrategy, never()).clearUserDataPoints();
+
+ // Verify that we add the data point once when the user sets it, and again when we return
+ // interactive mode.
+ verify(mBrightnessMappingStrategy, times(2))
+ .addUserDataPoint(123.0f, 0.51f);
+ }
+
+ @Test
+ public void testShortTermModelIsRestoredWhenSwitchingWithinTimeout() throws Exception {
+ ArgumentCaptor<SensorEventListener> listenerCaptor =
+ ArgumentCaptor.forClass(SensorEventListener.class);
+ verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor),
+ eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class));
+ SensorEventListener listener = listenerCaptor.getValue();
+
+ // Sensor reads 123 lux,
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 123));
+ // User sets brightness to 100
+ mController.configure(AUTO_BRIGHTNESS_ENABLED, /* configuration= */ null,
+ /* brightness= */ 0.5f, /* userChangedBrightness= */ true, /* adjustment= */ 0,
+ /* userChanged= */ false, DisplayPowerRequest.POLICY_BRIGHT,
+ /* shouldResetShortTermModel= */ true);
+
+ when(mBrightnessMappingStrategy.getShortTermModelTimeout()).thenReturn(2000L);
+ when(mBrightnessMappingStrategy.getUserBrightness()).thenReturn(0.5f);
+ when(mBrightnessMappingStrategy.getUserLux()).thenReturn(123f);
+
+ mController.switchToIdleMode();
+ when(mIdleBrightnessMappingStrategy.isForIdleMode()).thenReturn(true);
+ when(mIdleBrightnessMappingStrategy.getUserBrightness()).thenReturn(-1f);
+ when(mIdleBrightnessMappingStrategy.getUserLux()).thenReturn(-1f);
+ when(mBrightnessMappingStrategy.shouldResetShortTermModel(
+ 123f, 0.5f)).thenReturn(true);
+
+ // Sensor reads 1000 lux,
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1000));
+ mTestLooper.moveTimeForward(
+ mBrightnessMappingStrategy.getShortTermModelTimeout() + 1000);
+ mTestLooper.dispatchAll();
+
+ mController.switchToInteractiveScreenBrightnessMode();
+ mTestLooper.moveTimeForward(4000);
+ mTestLooper.dispatchAll();
+
+ // Verify only happens on the first configure. (i.e. not again when switching back)
+ // Intentionally using any() to ensure it's not called whatsoever.
+ verify(mBrightnessMappingStrategy, times(1))
+ .addUserDataPoint(123.0f, 0.5f);
+ verify(mBrightnessMappingStrategy, times(1))
+ .addUserDataPoint(anyFloat(), anyFloat());
+ }
+
+ @Test
+ public void testShortTermModelNotRestoredAfterTimeout() throws Exception {
+ ArgumentCaptor<SensorEventListener> listenerCaptor =
+ ArgumentCaptor.forClass(SensorEventListener.class);
+ verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor),
+ eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class));
+ SensorEventListener listener = listenerCaptor.getValue();
+
+ // Sensor reads 123 lux,
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 123));
+ // User sets brightness to 100
+ mController.configure(AUTO_BRIGHTNESS_ENABLED, /* configuration= */ null,
+ /* brightness= */ 0.5f, /* userChangedBrightness= */ true, /* adjustment= */ 0,
+ /* userChanged= */ false, DisplayPowerRequest.POLICY_BRIGHT,
+ /* shouldResetShortTermModel= */ true);
+
+ when(mBrightnessMappingStrategy.getShortTermModelTimeout()).thenReturn(2000L);
+
+ when(mBrightnessMappingStrategy.getUserBrightness()).thenReturn(0.5f);
+ when(mBrightnessMappingStrategy.getUserLux()).thenReturn(123f);
+
+ mController.switchToIdleMode();
+ when(mIdleBrightnessMappingStrategy.isForIdleMode()).thenReturn(true);
+ when(mIdleBrightnessMappingStrategy.getUserBrightness()).thenReturn(-1f);
+ when(mIdleBrightnessMappingStrategy.getUserLux()).thenReturn(-1f);
+
+ when(mBrightnessMappingStrategy.shouldResetShortTermModel(
+ 123f, 0.5f)).thenReturn(true);
+
+ // Sensor reads 1000 lux,
+ listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1000));
+ // Do not fast-forward time.
+ mTestLooper.dispatchAll();
+
+ mController.switchToInteractiveScreenBrightnessMode();
+ // Do not fast-forward time
+ mTestLooper.dispatchAll();
+
+ // Verify this happens on the first configure and again when switching back
+ // Intentionally using any() to ensure it's not called any other times whatsoever.
+ verify(mBrightnessMappingStrategy, times(2))
+ .addUserDataPoint(123.0f, 0.5f);
+ verify(mBrightnessMappingStrategy, times(2))
+ .addUserDataPoint(anyFloat(), anyFloat());
+ }
+
+ @Test
public void testSwitchToIdleMappingStrategy() throws Exception {
ArgumentCaptor<SensorEventListener> listenerCaptor =
ArgumentCaptor.forClass(SensorEventListener.class);
@@ -326,6 +499,11 @@
// Called once for init, and once when switching,
// setAmbientLux() is called twice and once in updateAutoBrightness()
verify(mBrightnessMappingStrategy, times(5)).isForIdleMode();
+ // Called when switching.
+ verify(mBrightnessMappingStrategy, times(1)).getShortTermModelTimeout();
+ verify(mBrightnessMappingStrategy, times(1)).getUserBrightness();
+ verify(mBrightnessMappingStrategy, times(1)).getUserLux();
+
// Ensure, after switching, original BMS is not used anymore
verifyNoMoreInteractions(mBrightnessMappingStrategy);
diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessThrottlerTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessThrottlerTest.java
index ffe2fec..ce4b438 100644
--- a/services/tests/servicestests/src/com/android/server/display/BrightnessThrottlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/BrightnessThrottlerTest.java
@@ -54,6 +54,7 @@
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
@SmallTest
@@ -122,8 +123,6 @@
BrightnessThrottlingData data;
data = BrightnessThrottlingData.create((List<ThrottlingLevel>)null);
assertEquals(data, null);
- data = BrightnessThrottlingData.create((BrightnessThrottlingData)null);
- assertEquals(data, null);
data = BrightnessThrottlingData.create(new ArrayList<ThrottlingLevel>());
assertEquals(data, null);
data = BrightnessThrottlingData.create(unsortedThermalLevels);
@@ -146,7 +145,7 @@
}
@Test
- public void testThrottlingUnsupported() throws Exception {
+ public void testThrottlingUnsupported() {
final BrightnessThrottler throttler = createThrottlerUnsupported();
assertFalse(throttler.deviceSupportsThrottling());
@@ -307,37 +306,18 @@
verify(mThermalServiceMock).registerThermalEventListenerWithType(
mThermalEventListenerCaptor.capture(), eq(Temperature.TYPE_SKIN));
final IThermalEventListener listener = mThermalEventListenerCaptor.getValue();
+ testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.4f);
- // Set status too low to trigger throttling
- listener.notifyThrottling(getSkinTemp(level.thermalStatus - 1));
- mTestLooper.dispatchAll();
- assertEquals(PowerManager.BRIGHTNESS_MAX, throttler.getBrightnessCap(), 0f);
- assertFalse(throttler.isThrottled());
-
- // Set status high enough to trigger throttling
- listener.notifyThrottling(getSkinTemp(level.thermalStatus));
- mTestLooper.dispatchAll();
- assertEquals(0.4f, throttler.getBrightnessCap(), 0f);
- assertTrue(throttler.isThrottled());
-
- // Update thresholds
- // This data is equivalent to the string "123,1,critical,0.8", passed below
- final ThrottlingLevel newLevel = new ThrottlingLevel(PowerManager.THERMAL_STATUS_CRITICAL,
- 0.8f);
// Set new (valid) data from device config
mDeviceConfigFake.setBrightnessThrottlingData("123,1,critical,0.8");
+ testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.8f);
- // Set status too low to trigger throttling
- listener.notifyThrottling(getSkinTemp(newLevel.thermalStatus - 1));
- mTestLooper.dispatchAll();
- assertEquals(PowerManager.BRIGHTNESS_MAX, throttler.getBrightnessCap(), 0f);
- assertFalse(throttler.isThrottled());
-
- // Set status high enough to trigger throttling
- listener.notifyThrottling(getSkinTemp(newLevel.thermalStatus));
- mTestLooper.dispatchAll();
- assertEquals(newLevel.brightness, throttler.getBrightnessCap(), 0f);
- assertTrue(throttler.isThrottled());
+ mDeviceConfigFake.setBrightnessThrottlingData(
+ "123,1,critical,0.75;123,1,critical,0.99,id_2");
+ testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.75f);
+ mDeviceConfigFake.setBrightnessThrottlingData(
+ "123,1,critical,0.8,default;123,1,critical,0.99,id_2");
+ testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.8f);
}
@Test public void testInvalidThrottlingStrings() throws Exception {
@@ -370,6 +350,18 @@
testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f);
mDeviceConfigFake.setBrightnessThrottlingData(""); // Invalid format
testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f);
+ // Invalid string format
+ mDeviceConfigFake.setBrightnessThrottlingData(
+ "123,default,1,critical,0.75,1,critical,0.99");
+ testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f);
+ // Invalid level string and number string
+ mDeviceConfigFake.setBrightnessThrottlingData(
+ "123,1,1,critical,0.75,id_2,1,critical,0.99");
+ testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f);
+ // Invalid format - (two default ids for same display)
+ mDeviceConfigFake.setBrightnessThrottlingData(
+ "123,1,critical,0.75,default;123,1,critical,0.99");
+ testThrottling(throttler, listener, PowerManager.BRIGHTNESS_MAX, 0.25f);
}
private void testThrottling(BrightnessThrottler throttler, IThermalEventListener listener,
@@ -472,13 +464,17 @@
}
private BrightnessThrottler createThrottlerUnsupported() {
- return new BrightnessThrottler(mInjectorMock, mHandler, mHandler, null, () -> {}, null);
+ return new BrightnessThrottler(mInjectorMock, mHandler, mHandler,
+ /* throttlingChangeCallback= */ () -> {}, /* uniqueDisplayId= */ null,
+ /* throttlingDataId= */ null, /* throttlingDataMap= */ new HashMap<>(1));
}
private BrightnessThrottler createThrottlerSupported(BrightnessThrottlingData data) {
assertNotNull(data);
+ HashMap<String, BrightnessThrottlingData> throttlingDataMap = new HashMap<>(1);
+ throttlingDataMap.put("default", data);
return new BrightnessThrottler(mInjectorMock, mHandler, BackgroundThread.getHandler(),
- data, () -> {}, "123");
+ () -> {}, "123", "default", throttlingDataMap);
}
private Temperature getSkinTemp(@ThrottlingStatus int status) {
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
index 9fd647b..ed07559 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
@@ -50,6 +50,7 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
@SmallTest
@@ -186,50 +187,72 @@
assertArrayEquals(new int[]{-1, 10, 20, 30, 40},
mDisplayDeviceConfig.getScreenOffBrightnessSensorValueToLux());
- List<DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel> throttlingLevels =
- new ArrayList();
- throttlingLevels.add(new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
+ List<DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel>
+ defaultThrottlingLevels = new ArrayList<>();
+ defaultThrottlingLevels.add(
+ new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
DisplayDeviceConfig.convertThermalStatus(ThermalStatus.light), 0.4f
));
- throttlingLevels.add(new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
+ defaultThrottlingLevels.add(
+ new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
DisplayDeviceConfig.convertThermalStatus(ThermalStatus.moderate), 0.3f
));
- throttlingLevels.add(new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
+ defaultThrottlingLevels.add(
+ new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
DisplayDeviceConfig.convertThermalStatus(ThermalStatus.severe), 0.2f
));
- throttlingLevels.add(new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
+ defaultThrottlingLevels.add(
+ new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
DisplayDeviceConfig.convertThermalStatus(ThermalStatus.critical), 0.1f
));
- throttlingLevels.add(new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
+ defaultThrottlingLevels.add(
+ new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
DisplayDeviceConfig.convertThermalStatus(ThermalStatus.emergency), 0.05f
));
- throttlingLevels.add(new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
+ defaultThrottlingLevels.add(
+ new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
DisplayDeviceConfig.convertThermalStatus(ThermalStatus.shutdown), 0.025f
));
- assertEquals(new DisplayDeviceConfig.BrightnessThrottlingData(throttlingLevels),
- mDisplayDeviceConfig.getBrightnessThrottlingData("default"));
- throttlingLevels.clear();
- throttlingLevels.add(new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
+ DisplayDeviceConfig.BrightnessThrottlingData defaultThrottlingData =
+ new DisplayDeviceConfig.BrightnessThrottlingData(defaultThrottlingLevels);
+
+ List<DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel>
+ concurrentThrottlingLevels = new ArrayList<>();
+ concurrentThrottlingLevels.add(
+ new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
DisplayDeviceConfig.convertThermalStatus(ThermalStatus.light), 0.2f
));
- throttlingLevels.add(new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
+ concurrentThrottlingLevels.add(
+ new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
DisplayDeviceConfig.convertThermalStatus(ThermalStatus.moderate), 0.15f
));
- throttlingLevels.add(new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
+ concurrentThrottlingLevels.add(
+ new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
DisplayDeviceConfig.convertThermalStatus(ThermalStatus.severe), 0.1f
));
- throttlingLevels.add(new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
+ concurrentThrottlingLevels.add(
+ new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
DisplayDeviceConfig.convertThermalStatus(ThermalStatus.critical), 0.05f
));
- throttlingLevels.add(new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
+ concurrentThrottlingLevels.add(
+ new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
DisplayDeviceConfig.convertThermalStatus(ThermalStatus.emergency), 0.025f
));
- throttlingLevels.add(new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
+ concurrentThrottlingLevels.add(
+ new DisplayDeviceConfig.BrightnessThrottlingData.ThrottlingLevel(
DisplayDeviceConfig.convertThermalStatus(ThermalStatus.shutdown), 0.0125f
));
- assertEquals(new DisplayDeviceConfig.BrightnessThrottlingData(throttlingLevels),
- mDisplayDeviceConfig.getBrightnessThrottlingData("concurrent"));
+ DisplayDeviceConfig.BrightnessThrottlingData concurrentThrottlingData =
+ new DisplayDeviceConfig.BrightnessThrottlingData(concurrentThrottlingLevels);
+
+ HashMap<String, DisplayDeviceConfig.BrightnessThrottlingData> throttlingDataMap =
+ new HashMap<>(2);
+ throttlingDataMap.put("default", defaultThrottlingData);
+ throttlingDataMap.put("concurrent", concurrentThrottlingData);
+
+ assertEquals(throttlingDataMap,
+ mDisplayDeviceConfig.getBrightnessThrottlingDataMapByThrottlingId());
assertNotNull(mDisplayDeviceConfig.getHostUsiVersion());
assertEquals(mDisplayDeviceConfig.getHostUsiVersion().getMajorVersion(), 2);
@@ -246,8 +269,7 @@
mDisplayDeviceConfig.getHdrBrightnessFromSdr(0.62f, 1.25f),
SMALL_DELTA);
-
- // Todo: Add asserts for BrightnessThrottlingData, DensityMapping,
+ // Todo: Add asserts for DensityMapping,
// HighBrightnessModeData AmbientLightSensor, RefreshRateLimitations and ProximitySensor.
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index dc954a2..1ba6ad7 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -4734,7 +4734,7 @@
}
@Test
- public void testBumpFGImportance_noChannelChangePreOApp() throws Exception {
+ public void testBumpFGImportance_channelChangePreOApp() throws Exception {
String preOPkg = PKG_N_MR1;
final ApplicationInfo legacy = new ApplicationInfo();
legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
@@ -4752,7 +4752,7 @@
.setPriority(Notification.PRIORITY_MIN);
StatusBarNotification sbn = new StatusBarNotification(preOPkg, preOPkg, 9,
- "testBumpFGImportance_noChannelChangePreOApp",
+ "testBumpFGImportance_channelChangePreOApp",
Binder.getCallingUid(), 0, nb.build(),
UserHandle.getUserHandleForUid(Binder.getCallingUid()), null, 0);
@@ -4772,11 +4772,11 @@
.setPriority(Notification.PRIORITY_MIN);
sbn = new StatusBarNotification(preOPkg, preOPkg, 9,
- "testBumpFGImportance_noChannelChangePreOApp", Binder.getCallingUid(),
+ "testBumpFGImportance_channelChangePreOApp", Binder.getCallingUid(),
0, nb.build(), UserHandle.getUserHandleForUid(Binder.getCallingUid()), null, 0);
mBinderService.enqueueNotificationWithTag(preOPkg, preOPkg,
- "testBumpFGImportance_noChannelChangePreOApp",
+ "testBumpFGImportance_channelChangePreOApp",
sbn.getId(), sbn.getNotification(), sbn.getUserId());
waitForIdle();
assertEquals(IMPORTANCE_LOW,
@@ -4784,7 +4784,7 @@
NotificationChannel defaultChannel = mBinderService.getNotificationChannel(
preOPkg, mContext.getUserId(), preOPkg, NotificationChannel.DEFAULT_CHANNEL_ID);
- assertEquals(IMPORTANCE_UNSPECIFIED, defaultChannel.getImportance());
+ assertEquals(IMPORTANCE_LOW, defaultChannel.getImportance());
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
index 893f538..3ba9400 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
@@ -120,12 +120,20 @@
.showLights(false)
.showBadges(false)
.showInAmbientDisplay(false)
+ .allowCalls(ZenPolicy.PEOPLE_TYPE_CONTACTS)
+ .allowMessages(ZenPolicy.PEOPLE_TYPE_STARRED)
+ .allowConversations(ZenPolicy.CONVERSATION_SENDERS_NONE)
.build();
ZenModeConfig config = getMutedAllConfig();
config.allowAlarms = true;
config.allowReminders = true;
config.allowEvents = true;
+ config.allowCalls = true;
+ config.allowCallsFrom = Policy.PRIORITY_SENDERS_CONTACTS;
+ config.allowMessages = true;
+ config.allowMessagesFrom = Policy.PRIORITY_SENDERS_STARRED;
+ config.allowConversations = false;
config.suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_BADGE;
config.suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_LIGHTS;
config.suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_AMBIENT;
@@ -138,6 +146,10 @@
assertEquals(expected.getPriorityCategoryEvents(), actual.getPriorityCategoryEvents());
assertEquals(expected.getVisualEffectLights(), actual.getVisualEffectLights());
assertEquals(expected.getVisualEffectAmbient(), actual.getVisualEffectAmbient());
+ assertEquals(expected.getPriorityConversationSenders(),
+ actual.getPriorityConversationSenders());
+ assertEquals(expected.getPriorityCallSenders(), actual.getPriorityCallSenders());
+ assertEquals(expected.getPriorityMessageSenders(), actual.getPriorityMessageSenders());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
index 12e4825..a15ee69 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
@@ -41,6 +41,7 @@
import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE;
import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE;
import static android.view.WindowManager.PROPERTY_COMPAT_ENABLE_FAKE_FOCUS;
+import static android.view.WindowManager.PROPERTY_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED;
import static android.view.WindowManager.PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -146,7 +147,7 @@
mActivity = setUpActivityWithComponent();
mController = new LetterboxUiController(mWm, mActivity);
prepareActivityThatShouldIgnoreRequestedOrientationDuringRelaunch();
- mController.setRelauchingAfterRequestedOrientationChanged(false);
+ mController.setRelaunchingAfterRequestedOrientationChanged(false);
spyOn(mDisplayContent.mDisplayRotationCompatPolicy);
doReturn(true).when(mDisplayContent.mDisplayRotationCompatPolicy)
@@ -190,6 +191,8 @@
@Test
public void testShouldIgnoreOrientationRequestLoop_overrideDisabled_returnsFalse() {
+ doReturn(true).when(mLetterboxConfiguration)
+ .isPolicyForIgnoringRequestedOrientationEnabled();
doReturn(false).when(mActivity).isLetterboxedForFixedOrientationAndAspectRatio();
// Request 3 times to simulate orientation request loop
for (int i = 0; i <= MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP; i++) {
@@ -200,8 +203,30 @@
@Test
@EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED})
+ public void testShouldIgnoreOrientationRequestLoop_propertyIsFalseAndOverride_returnsFalse()
+ throws Exception {
+ doReturn(true).when(mLetterboxConfiguration)
+ .isPolicyForIgnoringRequestedOrientationEnabled();
+ mockThatProperty(PROPERTY_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED,
+ /* value */ false);
+ doReturn(false).when(mActivity).isLetterboxedForFixedOrientationAndAspectRatio();
+
+ mController = new LetterboxUiController(mWm, mActivity);
+
+ // Request 3 times to simulate orientation request loop
+ for (int i = 0; i <= MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP; i++) {
+ assertShouldIgnoreOrientationRequestLoop(/* shouldIgnore */ false,
+ /* expectedCount */ 0);
+ }
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED})
public void testShouldIgnoreOrientationRequestLoop_isLetterboxed_returnsFalse() {
+ doReturn(true).when(mLetterboxConfiguration)
+ .isPolicyForIgnoringRequestedOrientationEnabled();
doReturn(true).when(mActivity).isLetterboxedForFixedOrientationAndAspectRatio();
+
// Request 3 times to simulate orientation request loop
for (int i = 0; i <= MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP; i++) {
assertShouldIgnoreOrientationRequestLoop(/* shouldIgnore */ false,
@@ -212,7 +237,10 @@
@Test
@EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED})
public void testShouldIgnoreOrientationRequestLoop_noLoop_returnsFalse() {
+ doReturn(true).when(mLetterboxConfiguration)
+ .isPolicyForIgnoringRequestedOrientationEnabled();
doReturn(false).when(mActivity).isLetterboxedForFixedOrientationAndAspectRatio();
+
// No orientation request loop
assertShouldIgnoreOrientationRequestLoop(/* shouldIgnore */ false,
/* expectedCount */ 0);
@@ -222,7 +250,10 @@
@EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED})
public void testShouldIgnoreOrientationRequestLoop_timeout_returnsFalse()
throws InterruptedException {
+ doReturn(true).when(mLetterboxConfiguration)
+ .isPolicyForIgnoringRequestedOrientationEnabled();
doReturn(false).when(mActivity).isLetterboxedForFixedOrientationAndAspectRatio();
+
for (int i = MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP; i > 0; i--) {
assertShouldIgnoreOrientationRequestLoop(/* shouldIgnore */ false,
/* expectedCount */ 0);
@@ -233,7 +264,10 @@
@Test
@EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED})
public void testShouldIgnoreOrientationRequestLoop_returnsTrue() {
+ doReturn(true).when(mLetterboxConfiguration)
+ .isPolicyForIgnoringRequestedOrientationEnabled();
doReturn(false).when(mActivity).isLetterboxedForFixedOrientationAndAspectRatio();
+
for (int i = 0; i < MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP; i++) {
assertShouldIgnoreOrientationRequestLoop(/* shouldIgnore */ false,
/* expectedCount */ i);
@@ -870,7 +904,7 @@
private void prepareActivityThatShouldIgnoreRequestedOrientationDuringRelaunch() {
doReturn(true).when(mLetterboxConfiguration)
.isPolicyForIgnoringRequestedOrientationEnabled();
- mController.setRelauchingAfterRequestedOrientationChanged(true);
+ mController.setRelaunchingAfterRequestedOrientationChanged(true);
}
private ActivityRecord setUpActivityWithComponent() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index a646d01..e96d1ab 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -813,6 +813,8 @@
spyOn(mActivity.mLetterboxUiController);
doReturn(true).when(mActivity.mLetterboxUiController)
+ .isSurfaceReadyToShow(any());
+ doReturn(true).when(mActivity.mLetterboxUiController)
.isSurfaceVisible(any());
assertTrue(mActivity.mLetterboxUiController.shouldShowLetterboxUi(