diff options
59 files changed, 1143 insertions, 973 deletions
diff --git a/cmds/idmap2/idmap2/CommandUtils.cpp b/cmds/idmap2/idmap2/CommandUtils.cpp index e058cd6e7e70..8f5845bf2e53 100644 --- a/cmds/idmap2/idmap2/CommandUtils.cpp +++ b/cmds/idmap2/idmap2/CommandUtils.cpp @@ -29,7 +29,7 @@ using android::idmap2::Result; using android::idmap2::Unit; Result<Unit> Verify(const std::string& idmap_path, const std::string& target_path, - const std::string& overlay_path, uint32_t fulfilled_policies, + const std::string& overlay_path, PolicyBitmask fulfilled_policies, bool enforce_overlayable) { SYSTRACE << "Verify " << idmap_path; std::ifstream fin(idmap_path); diff --git a/cmds/idmap2/idmap2/CommandUtils.h b/cmds/idmap2/idmap2/CommandUtils.h index 99605de30988..e717e046d15d 100644 --- a/cmds/idmap2/idmap2/CommandUtils.h +++ b/cmds/idmap2/idmap2/CommandUtils.h @@ -17,12 +17,13 @@ #ifndef IDMAP2_IDMAP2_COMMAND_UTILS_H_ #define IDMAP2_IDMAP2_COMMAND_UTILS_H_ +#include "idmap2/PolicyUtils.h" #include "idmap2/Result.h" android::idmap2::Result<android::idmap2::Unit> Verify(const std::string& idmap_path, const std::string& target_path, const std::string& overlay_path, - uint32_t fulfilled_policies, + PolicyBitmask fulfilled_policies, bool enforce_overlayable); #endif // IDMAP2_IDMAP2_COMMAND_UTILS_H_ diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp index 908d96612269..f95b73f17222 100644 --- a/cmds/idmap2/idmap2d/Idmap2Service.cpp +++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp @@ -70,12 +70,12 @@ PolicyBitmask ConvertAidlArgToPolicyBitmask(int32_t arg) { } Status GetCrc(const std::string& apk_path, uint32_t* out_crc) { - const auto overlay_zip = ZipFile::Open(apk_path); - if (!overlay_zip) { + const auto zip = ZipFile::Open(apk_path); + if (!zip) { return error(StringPrintf("failed to open apk %s", apk_path.c_str())); } - const auto crc = GetPackageCrc(*overlay_zip); + const auto crc = GetPackageCrc(*zip); if (!crc) { return error(crc.GetErrorMessage()); } @@ -121,6 +121,7 @@ Status Idmap2Service::verifyIdmap(const std::string& target_apk_path, bool* _aidl_return) { SYSTRACE << "Idmap2Service::verifyIdmap " << overlay_apk_path; assert(_aidl_return); + const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path); std::ifstream fin(idmap_path); const std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(fin); @@ -156,13 +157,10 @@ Status Idmap2Service::verifyIdmap(const std::string& target_apk_path, auto up_to_date = header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(), target_crc, overlay_crc, - fulfilled_policies, enforce_overlayable); - if (!up_to_date) { - *_aidl_return = false; - return error(up_to_date.GetErrorMessage()); - } + ConvertAidlArgToPolicyBitmask(fulfilled_policies), enforce_overlayable); - return ok(); + *_aidl_return = static_cast<bool>(up_to_date); + return *_aidl_return ? ok() : error(up_to_date.GetErrorMessage()); } Status Idmap2Service::createIdmap(const std::string& target_apk_path, diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h index 8f25b8d6a734..0f05592b70f3 100644 --- a/cmds/idmap2/include/idmap2/Idmap.h +++ b/cmds/idmap2/include/idmap2/Idmap.h @@ -141,9 +141,9 @@ class IdmapHeader { // field *must* be incremented. Because of this, we know that if the idmap // header is up-to-date the entire file is up-to-date. Result<Unit> IsUpToDate(const char* target_path, const char* overlay_path, - uint32_t fulfilled_policies, bool enforce_overlayable) const; + PolicyBitmask fulfilled_policies, bool enforce_overlayable) const; Result<Unit> IsUpToDate(const char* target_path, const char* overlay_path, uint32_t target_crc, - uint32_t overlay_crc, uint32_t fulfilled_policies, + uint32_t overlay_crc, PolicyBitmask fulfilled_policies, bool enforce_overlayable) const; void accept(Visitor* v) const; diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp index 0bea21735b24..23c25a7089de 100644 --- a/cmds/idmap2/libidmap2/Idmap.cpp +++ b/cmds/idmap2/libidmap2/Idmap.cpp @@ -115,8 +115,7 @@ std::unique_ptr<const IdmapHeader> IdmapHeader::FromBinaryStream(std::istream& s uint8_t enforce_overlayable; if (!Read32(stream, &idmap_header->magic_) || !Read32(stream, &idmap_header->version_) || !Read32(stream, &idmap_header->target_crc_) || !Read32(stream, &idmap_header->overlay_crc_) || - !Read32(stream, &idmap_header->fulfilled_policies_) || - !Read8(stream, &enforce_overlayable) || + !Read32(stream, &idmap_header->fulfilled_policies_) || !Read8(stream, &enforce_overlayable) || !ReadString256(stream, idmap_header->target_path_) || !ReadString256(stream, idmap_header->overlay_path_)) { return nullptr; @@ -134,7 +133,8 @@ std::unique_ptr<const IdmapHeader> IdmapHeader::FromBinaryStream(std::istream& s } Result<Unit> IdmapHeader::IsUpToDate(const char* target_path, const char* overlay_path, - uint32_t fulfilled_policies, bool enforce_overlayable) const { + PolicyBitmask fulfilled_policies, + bool enforce_overlayable) const { const std::unique_ptr<const ZipFile> target_zip = ZipFile::Open(target_path); if (!target_zip) { return Error("failed to open target %s", target_path); @@ -161,7 +161,8 @@ Result<Unit> IdmapHeader::IsUpToDate(const char* target_path, const char* overla Result<Unit> IdmapHeader::IsUpToDate(const char* target_path, const char* overlay_path, uint32_t target_crc, uint32_t overlay_crc, - uint32_t fulfilled_policies, bool enforce_overlayable) const { + PolicyBitmask fulfilled_policies, + bool enforce_overlayable) const { if (magic_ != kIdmapMagic) { return Error("bad magic: actual 0x%08x, expected 0x%08x", magic_, kIdmapMagic); } @@ -187,8 +188,7 @@ Result<Unit> IdmapHeader::IsUpToDate(const char* target_path, const char* overla if (enforce_overlayable != enforce_overlayable_) { return Error("bad enforce overlayable: idmap version %s, file system version %s", - enforce_overlayable ? "true" : "false", - enforce_overlayable_ ? "true" : "false"); + enforce_overlayable ? "true" : "false", enforce_overlayable_ ? "true" : "false"); } if (strcmp(target_path, target_path_) != 0) { diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index e2fd511a222b..1823bad0076d 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -193,7 +193,7 @@ message Atom { BiometricAcquired biometric_acquired = 87 [(module) = "framework"]; BiometricAuthenticated biometric_authenticated = 88 [(module) = "framework"]; BiometricErrorOccurred biometric_error_occurred = 89 [(module) = "framework"]; - UiEventReported ui_event_reported = 90 [(module) = "framework"]; + UiEventReported ui_event_reported = 90 [(module) = "framework", (module) = "sysui"]; BatteryHealthSnapshot battery_health_snapshot = 91; SlowIo slow_io = 92; BatteryCausedShutdown battery_caused_shutdown = 93; @@ -419,7 +419,7 @@ message Atom { DisplayJankReported display_jank_reported = 257; AppStandbyBucketChanged app_standby_bucket_changed = 258 [(module) = "framework"]; SharesheetStarted sharesheet_started = 259 [(module) = "framework"]; - RankingSelected ranking_selected = 260 [(module) = "framework"]; + RankingSelected ranking_selected = 260 [(module) = "framework", (module) = "sysui"]; TvSettingsUIInteracted tvsettings_ui_interacted = 261 [(module) = "tv_settings"]; LauncherStaticLayout launcher_snapshot = 262 [(module) = "sysui"]; PackageInstallerV2Reported package_installer_v2_reported = 263 [(module) = "framework"]; diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index 6bbc37a90fae..7f834afd7b30 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -586,13 +586,27 @@ public final class CameraManager { * priority when accessing the camera, and this method will succeed even if the camera device is * in use by another camera API client. Any lower-priority application that loses control of the * camera in this way will receive an - * {@link android.hardware.camera2.CameraDevice.StateCallback#onDisconnected} callback.</p> + * {@link android.hardware.camera2.CameraDevice.StateCallback#onDisconnected} callback. + * Opening the same camera ID twice in the same application will similarly cause the + * {@link android.hardware.camera2.CameraDevice.StateCallback#onDisconnected} callback + * being fired for the {@link CameraDevice} from the first open call and all ongoing tasks + * being droppped.</p> * * <p>Once the camera is successfully opened, {@link CameraDevice.StateCallback#onOpened} will * be invoked with the newly opened {@link CameraDevice}. The camera device can then be set up * for operation by calling {@link CameraDevice#createCaptureSession} and * {@link CameraDevice#createCaptureRequest}</p> * + * <p>Before API level 30, when the application tries to open multiple {@link CameraDevice} of + * different IDs and the device does not support opening such combination, either the + * {@link #openCamera} will fail and throw a {@link CameraAccessException} or one or more of + * already opened {@link CameraDevice} will be disconnected and receive + * {@link android.hardware.camera2.CameraDevice.StateCallback#onDisconnected} callback. Which + * behavior will happen depends on the device implementation and can vary on different devices. + * Starting in API level 30, if the device does not support the combination of cameras being + * opened, it is guaranteed the {@link #openCamera} call will fail and none of existing + * {@link CameraDevice} will be disconnected.</p> + * * <!-- * <p>Since the camera device will be opened asynchronously, any asynchronous operations done * on the returned CameraDevice instance will be queued up until the device startup has @@ -618,7 +632,8 @@ public final class CameraManager { * {@code null} to use the current thread's {@link android.os.Looper looper}. * * @throws CameraAccessException if the camera is disabled by device policy, - * has been disconnected, or is being used by a higher-priority camera API client. + * has been disconnected, is being used by a higher-priority camera API client, or the device + * has reached its maximal resource and cannot open this camera device. * * @throws IllegalArgumentException if cameraId or the callback was null, * or the cameraId does not match any currently or previously available diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index 23c86029f3be..6d49add65c5b 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -1072,7 +1072,7 @@ public class CameraDeviceImpl extends CameraDevice * @param lastFrameNumber last frame number returned from binder. * @param repeatingRequestTypes the repeating requests' types. */ - private void checkEarlyTriggerSequenceCompleteLocked( + private void checkEarlyTriggerSequenceComplete( final int requestId, final long lastFrameNumber, final int[] repeatingRequestTypes) { // lastFrameNumber being equal to NO_FRAMES_CAPTURED means that the request @@ -1212,7 +1212,7 @@ public class CameraDeviceImpl extends CameraDevice if (repeating) { if (mRepeatingRequestId != REQUEST_ID_NONE) { - checkEarlyTriggerSequenceCompleteLocked(mRepeatingRequestId, + checkEarlyTriggerSequenceComplete(mRepeatingRequestId, requestInfo.getLastFrameNumber(), mRepeatingRequestTypes); } @@ -1269,7 +1269,7 @@ public class CameraDeviceImpl extends CameraDevice return; } - checkEarlyTriggerSequenceCompleteLocked(requestId, lastFrameNumber, requestTypes); + checkEarlyTriggerSequenceComplete(requestId, lastFrameNumber, requestTypes); } } } @@ -1302,7 +1302,7 @@ public class CameraDeviceImpl extends CameraDevice long lastFrameNumber = mRemoteDevice.flush(); if (mRepeatingRequestId != REQUEST_ID_NONE) { - checkEarlyTriggerSequenceCompleteLocked(mRepeatingRequestId, lastFrameNumber, + checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber, mRepeatingRequestTypes); mRepeatingRequestId = REQUEST_ID_NONE; mRepeatingRequestTypes = null; @@ -1442,135 +1442,78 @@ public class CameraDeviceImpl extends CameraDevice long completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber(); long completedReprocessFrameNumber = mFrameNumberTracker.getCompletedReprocessFrameNumber(); long completedZslStillFrameNumber = mFrameNumberTracker.getCompletedZslStillFrameNumber(); - + boolean isReprocess = false; Iterator<RequestLastFrameNumbersHolder> iter = mRequestLastFrameNumbersList.iterator(); while (iter.hasNext()) { final RequestLastFrameNumbersHolder requestLastFrameNumbers = iter.next(); + boolean sequenceCompleted = false; final int requestId = requestLastFrameNumbers.getRequestId(); final CaptureCallbackHolder holder; - if (mRemoteDevice == null) { - Log.w(TAG, "Camera closed while checking sequences"); - return; - } - if (!requestLastFrameNumbers.isSequenceCompleted()) { - long lastRegularFrameNumber = - requestLastFrameNumbers.getLastRegularFrameNumber(); - long lastReprocessFrameNumber = - requestLastFrameNumbers.getLastReprocessFrameNumber(); - long lastZslStillFrameNumber = - requestLastFrameNumbers.getLastZslStillFrameNumber(); - if (lastRegularFrameNumber <= completedFrameNumber - && lastReprocessFrameNumber <= completedReprocessFrameNumber - && lastZslStillFrameNumber <= completedZslStillFrameNumber) { - Log.v(TAG, String.format( - "Mark requestId %d as completed, because lastRegularFrame %d " - + "is <= %d, lastReprocessFrame %d is <= %d, " - + "lastZslStillFrame %d is <= %d", requestId, - lastRegularFrameNumber, completedFrameNumber, - lastReprocessFrameNumber, completedReprocessFrameNumber, - lastZslStillFrameNumber, completedZslStillFrameNumber)); - requestLastFrameNumbers.markSequenceCompleted(); + synchronized(mInterfaceLock) { + if (mRemoteDevice == null) { + Log.w(TAG, "Camera closed while checking sequences"); + return; } - // Call onCaptureSequenceCompleted int index = mCaptureCallbackMap.indexOfKey(requestId); holder = (index >= 0) ? mCaptureCallbackMap.valueAt(index) : null; - if (holder != null && requestLastFrameNumbers.isSequenceCompleted()) { - Runnable resultDispatch = new Runnable() { - @Override - public void run() { - if (!CameraDeviceImpl.this.isClosed()){ - if (DEBUG) { - Log.d(TAG, String.format( - "fire sequence complete for request %d", - requestId)); - } - - holder.getCallback().onCaptureSequenceCompleted( - CameraDeviceImpl.this, - requestId, - requestLastFrameNumbers.getLastFrameNumber()); - } + if (holder != null) { + long lastRegularFrameNumber = + requestLastFrameNumbers.getLastRegularFrameNumber(); + long lastReprocessFrameNumber = + requestLastFrameNumbers.getLastReprocessFrameNumber(); + long lastZslStillFrameNumber = + requestLastFrameNumbers.getLastZslStillFrameNumber(); + // check if it's okay to remove request from mCaptureCallbackMap + if (lastRegularFrameNumber <= completedFrameNumber + && lastReprocessFrameNumber <= completedReprocessFrameNumber + && lastZslStillFrameNumber <= completedZslStillFrameNumber) { + sequenceCompleted = true; + mCaptureCallbackMap.removeAt(index); + if (DEBUG) { + Log.v(TAG, String.format( + "Remove holder for requestId %d, because lastRegularFrame %d " + + "is <= %d, lastReprocessFrame %d is <= %d, " + + "lastZslStillFrame %d is <= %d", requestId, + lastRegularFrameNumber, completedFrameNumber, + lastReprocessFrameNumber, completedReprocessFrameNumber, + lastZslStillFrameNumber, completedZslStillFrameNumber)); } - }; - final long ident = Binder.clearCallingIdentity(); - try { - holder.getExecutor().execute(resultDispatch); - } finally { - Binder.restoreCallingIdentity(ident); } } } - if (requestLastFrameNumbers.isSequenceCompleted() && - requestLastFrameNumbers.isInflightCompleted()) { - int index = mCaptureCallbackMap.indexOfKey(requestId); - if (index >= 0) { - mCaptureCallbackMap.removeAt(index); - } - if (DEBUG) { - Log.v(TAG, String.format( - "Remove holder for requestId %d", requestId)); - } + // If no callback is registered for this requestId or sequence completed, remove it + // from the frame number->request pair because it's not needed anymore. + if (holder == null || sequenceCompleted) { iter.remove(); } - } - } - - private void removeCompletedCallbackHolderLocked(long lastCompletedRegularFrameNumber, - long lastCompletedReprocessFrameNumber, long lastCompletedZslStillFrameNumber) { - if (DEBUG) { - Log.v(TAG, String.format("remove completed callback holders for " - + "lastCompletedRegularFrameNumber %d, " - + "lastCompletedReprocessFrameNumber %d, " - + "lastCompletedZslStillFrameNumber %d", - lastCompletedRegularFrameNumber, - lastCompletedReprocessFrameNumber, - lastCompletedZslStillFrameNumber)); - } - - Iterator<RequestLastFrameNumbersHolder> iter = mRequestLastFrameNumbersList.iterator(); - while (iter.hasNext()) { - final RequestLastFrameNumbersHolder requestLastFrameNumbers = iter.next(); - final int requestId = requestLastFrameNumbers.getRequestId(); - final CaptureCallbackHolder holder; - if (mRemoteDevice == null) { - Log.w(TAG, "Camera closed while removing completed callback holders"); - return; - } - long lastRegularFrameNumber = - requestLastFrameNumbers.getLastRegularFrameNumber(); - long lastReprocessFrameNumber = - requestLastFrameNumbers.getLastReprocessFrameNumber(); - long lastZslStillFrameNumber = - requestLastFrameNumbers.getLastZslStillFrameNumber(); - - if (lastRegularFrameNumber <= lastCompletedRegularFrameNumber - && lastReprocessFrameNumber <= lastCompletedReprocessFrameNumber - && lastZslStillFrameNumber <= lastCompletedZslStillFrameNumber) { + // Call onCaptureSequenceCompleted + if (sequenceCompleted) { + Runnable resultDispatch = new Runnable() { + @Override + public void run() { + if (!CameraDeviceImpl.this.isClosed()){ + if (DEBUG) { + Log.d(TAG, String.format( + "fire sequence complete for request %d", + requestId)); + } - if (requestLastFrameNumbers.isSequenceCompleted()) { - int index = mCaptureCallbackMap.indexOfKey(requestId); - if (index >= 0) { - mCaptureCallbackMap.removeAt(index); - } - if (DEBUG) { - Log.v(TAG, String.format( - "Remove holder for requestId %d, because lastRegularFrame %d " - + "is <= %d, lastReprocessFrame %d is <= %d, " - + "lastZslStillFrame %d is <= %d", requestId, - lastRegularFrameNumber, lastCompletedRegularFrameNumber, - lastReprocessFrameNumber, lastCompletedReprocessFrameNumber, - lastZslStillFrameNumber, lastCompletedZslStillFrameNumber)); - } - iter.remove(); - } else { - if (DEBUG) { - Log.v(TAG, "Sequence not yet completed for request id " + requestId); + holder.getCallback().onCaptureSequenceCompleted( + CameraDeviceImpl.this, + requestId, + requestLastFrameNumbers.getLastFrameNumber()); + } } - requestLastFrameNumbers.markInflightCompleted(); + }; + final long ident = Binder.clearCallingIdentity(); + try { + holder.getExecutor().execute(resultDispatch); + } finally { + Binder.restoreCallingIdentity(ident); } } } @@ -1759,12 +1702,6 @@ public class CameraDeviceImpl extends CameraDevice return; } - // Remove all capture callbacks now that device has gone to IDLE state. - removeCompletedCallbackHolderLocked( - Long.MAX_VALUE, /*lastCompletedRegularFrameNumber*/ - Long.MAX_VALUE, /*lastCompletedReprocessFrameNumber*/ - Long.MAX_VALUE /*lastCompletedZslStillFrameNumber*/); - if (!CameraDeviceImpl.this.mIdle) { final long ident = Binder.clearCallingIdentity(); try { @@ -1810,7 +1747,7 @@ public class CameraDeviceImpl extends CameraDevice return; } - checkEarlyTriggerSequenceCompleteLocked(mRepeatingRequestId, lastFrameNumber, + checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber, mRepeatingRequestTypes); // Check if there is already a new repeating request if (mRepeatingRequestId == repeatingRequestId) { @@ -1829,18 +1766,9 @@ public class CameraDeviceImpl extends CameraDevice public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) { int requestId = resultExtras.getRequestId(); final long frameNumber = resultExtras.getFrameNumber(); - final long lastCompletedRegularFrameNumber = - resultExtras.getLastCompletedRegularFrameNumber(); - final long lastCompletedReprocessFrameNumber = - resultExtras.getLastCompletedReprocessFrameNumber(); - final long lastCompletedZslFrameNumber = - resultExtras.getLastCompletedZslFrameNumber(); if (DEBUG) { - Log.d(TAG, "Capture started for id " + requestId + " frame number " + frameNumber - + ": completedRegularFrameNumber " + lastCompletedRegularFrameNumber - + ", completedReprocessFrameNUmber " + lastCompletedReprocessFrameNumber - + ", completedZslFrameNumber " + lastCompletedZslFrameNumber); + Log.d(TAG, "Capture started for id " + requestId + " frame number " + frameNumber); } final CaptureCallbackHolder holder; @@ -1856,12 +1784,6 @@ public class CameraDeviceImpl extends CameraDevice return; } - // Check if it's okay to remove completed callbacks from mCaptureCallbackMap. - // A callback is completed if the corresponding inflight request has been removed - // from the inflight queue in cameraservice. - removeCompletedCallbackHolderLocked(lastCompletedRegularFrameNumber, - lastCompletedReprocessFrameNumber, lastCompletedZslFrameNumber); - // Get the callback for this frame ID, if there is one holder = CameraDeviceImpl.this.mCaptureCallbackMap.get(requestId); diff --git a/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java index 413caf5e22e0..1d9d644c9306 100644 --- a/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java @@ -182,12 +182,6 @@ public class CameraOfflineSessionImpl extends CameraOfflineSession return; } - // Remove all capture callbacks now that device has gone to IDLE state. - removeCompletedCallbackHolderLocked( - Long.MAX_VALUE, /*lastCompletedRegularFrameNumber*/ - Long.MAX_VALUE, /*lastCompletedReprocessFrameNumber*/ - Long.MAX_VALUE /*lastCompletedZslStillFrameNumber*/); - Runnable idleDispatch = new Runnable() { @Override public void run() { @@ -210,22 +204,10 @@ public class CameraOfflineSessionImpl extends CameraOfflineSession public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) { int requestId = resultExtras.getRequestId(); final long frameNumber = resultExtras.getFrameNumber(); - final long lastCompletedRegularFrameNumber = - resultExtras.getLastCompletedRegularFrameNumber(); - final long lastCompletedReprocessFrameNumber = - resultExtras.getLastCompletedReprocessFrameNumber(); - final long lastCompletedZslFrameNumber = - resultExtras.getLastCompletedZslFrameNumber(); final CaptureCallbackHolder holder; synchronized(mInterfaceLock) { - // Check if it's okay to remove completed callbacks from mCaptureCallbackMap. - // A callback is completed if the corresponding inflight request has been removed - // from the inflight queue in cameraservice. - removeCompletedCallbackHolderLocked(lastCompletedRegularFrameNumber, - lastCompletedReprocessFrameNumber, lastCompletedZslFrameNumber); - // Get the callback for this frame ID, if there is one holder = CameraOfflineSessionImpl.this.mCaptureCallbackMap.get(requestId); @@ -619,61 +601,6 @@ public class CameraOfflineSessionImpl extends CameraOfflineSession } } - private void removeCompletedCallbackHolderLocked(long lastCompletedRegularFrameNumber, - long lastCompletedReprocessFrameNumber, long lastCompletedZslStillFrameNumber) { - if (DEBUG) { - Log.v(TAG, String.format("remove completed callback holders for " - + "lastCompletedRegularFrameNumber %d, " - + "lastCompletedReprocessFrameNumber %d, " - + "lastCompletedZslStillFrameNumber %d", - lastCompletedRegularFrameNumber, - lastCompletedReprocessFrameNumber, - lastCompletedZslStillFrameNumber)); - } - - boolean isReprocess = false; - Iterator<RequestLastFrameNumbersHolder> iter = - mOfflineRequestLastFrameNumbersList.iterator(); - while (iter.hasNext()) { - final RequestLastFrameNumbersHolder requestLastFrameNumbers = iter.next(); - final int requestId = requestLastFrameNumbers.getRequestId(); - final CaptureCallbackHolder holder; - - int index = mCaptureCallbackMap.indexOfKey(requestId); - holder = (index >= 0) ? - mCaptureCallbackMap.valueAt(index) : null; - if (holder != null) { - long lastRegularFrameNumber = - requestLastFrameNumbers.getLastRegularFrameNumber(); - long lastReprocessFrameNumber = - requestLastFrameNumbers.getLastReprocessFrameNumber(); - long lastZslStillFrameNumber = - requestLastFrameNumbers.getLastZslStillFrameNumber(); - if (lastRegularFrameNumber <= lastCompletedRegularFrameNumber - && lastReprocessFrameNumber <= lastCompletedReprocessFrameNumber - && lastZslStillFrameNumber <= lastCompletedZslStillFrameNumber) { - if (requestLastFrameNumbers.isSequenceCompleted()) { - mCaptureCallbackMap.removeAt(index); - if (DEBUG) { - Log.v(TAG, String.format( - "Remove holder for requestId %d, because lastRegularFrame %d " - + "is <= %d, lastReprocessFrame %d is <= %d, " - + "lastZslStillFrame %d is <= %d", requestId, - lastRegularFrameNumber, lastCompletedRegularFrameNumber, - lastReprocessFrameNumber, lastCompletedReprocessFrameNumber, - lastZslStillFrameNumber, lastCompletedZslStillFrameNumber)); - } - - iter.remove(); - } else { - Log.e(TAG, "Sequence not yet completed for request id " + requestId); - continue; - } - } - } - } - } - public void notifyFailedSwitch() { synchronized(mInterfaceLock) { Runnable switchFailDispatch = new Runnable() { diff --git a/core/java/android/hardware/camera2/impl/CaptureResultExtras.java b/core/java/android/hardware/camera2/impl/CaptureResultExtras.java index 5d9da73fd5c0..1ff5bd562f2e 100644 --- a/core/java/android/hardware/camera2/impl/CaptureResultExtras.java +++ b/core/java/android/hardware/camera2/impl/CaptureResultExtras.java @@ -30,9 +30,6 @@ public class CaptureResultExtras implements Parcelable { private int partialResultCount; private int errorStreamId; private String errorPhysicalCameraId; - private long lastCompletedRegularFrameNumber; - private long lastCompletedReprocessFrameNumber; - private long lastCompletedZslFrameNumber; public static final @android.annotation.NonNull Parcelable.Creator<CaptureResultExtras> CREATOR = new Parcelable.Creator<CaptureResultExtras>() { @@ -54,9 +51,7 @@ public class CaptureResultExtras implements Parcelable { public CaptureResultExtras(int requestId, int subsequenceId, int afTriggerId, int precaptureTriggerId, long frameNumber, int partialResultCount, int errorStreamId, - String errorPhysicalCameraId, long lastCompletedRegularFrameNumber, - long lastCompletedReprocessFrameNumber, - long lastCompletedZslFrameNumber) { + String errorPhysicalCameraId) { this.requestId = requestId; this.subsequenceId = subsequenceId; this.afTriggerId = afTriggerId; @@ -65,9 +60,6 @@ public class CaptureResultExtras implements Parcelable { this.partialResultCount = partialResultCount; this.errorStreamId = errorStreamId; this.errorPhysicalCameraId = errorPhysicalCameraId; - this.lastCompletedRegularFrameNumber = lastCompletedRegularFrameNumber; - this.lastCompletedReprocessFrameNumber = lastCompletedReprocessFrameNumber; - this.lastCompletedZslFrameNumber = lastCompletedZslFrameNumber; } @Override @@ -90,9 +82,6 @@ public class CaptureResultExtras implements Parcelable { } else { dest.writeBoolean(false); } - dest.writeLong(lastCompletedRegularFrameNumber); - dest.writeLong(lastCompletedReprocessFrameNumber); - dest.writeLong(lastCompletedZslFrameNumber); } public void readFromParcel(Parcel in) { @@ -107,9 +96,6 @@ public class CaptureResultExtras implements Parcelable { if (errorPhysicalCameraIdPresent) { errorPhysicalCameraId = in.readString(); } - lastCompletedRegularFrameNumber = in.readLong(); - lastCompletedReprocessFrameNumber = in.readLong(); - lastCompletedZslFrameNumber = in.readLong(); } public String getErrorPhysicalCameraId() { @@ -143,16 +129,4 @@ public class CaptureResultExtras implements Parcelable { public int getErrorStreamId() { return errorStreamId; } - - public long getLastCompletedRegularFrameNumber() { - return lastCompletedRegularFrameNumber; - } - - public long getLastCompletedReprocessFrameNumber() { - return lastCompletedReprocessFrameNumber; - } - - public long getLastCompletedZslFrameNumber() { - return lastCompletedZslFrameNumber; - } } diff --git a/core/java/android/hardware/camera2/impl/RequestLastFrameNumbersHolder.java b/core/java/android/hardware/camera2/impl/RequestLastFrameNumbersHolder.java index 0ee4ebc1aa87..bd1df9e1ac7d 100644 --- a/core/java/android/hardware/camera2/impl/RequestLastFrameNumbersHolder.java +++ b/core/java/android/hardware/camera2/impl/RequestLastFrameNumbersHolder.java @@ -38,10 +38,6 @@ public class RequestLastFrameNumbersHolder { // The last ZSL still capture frame number for this request ID. It's // CaptureCallback.NO_FRAMES_CAPTURED if the request ID has no zsl request. private final long mLastZslStillFrameNumber; - // Whether the sequence is completed. (only consider capture result) - private boolean mSequenceCompleted; - // Whether the inflight request is completed. (consider result, buffers, and notifies) - private boolean mInflightCompleted; /** * Create a request-last-frame-numbers holder with a list of requests, request ID, and @@ -93,8 +89,6 @@ public class RequestLastFrameNumbersHolder { mLastReprocessFrameNumber = lastReprocessFrameNumber; mLastZslStillFrameNumber = lastZslStillFrameNumber; mRequestId = requestInfo.getRequestId(); - mSequenceCompleted = false; - mInflightCompleted = false; } /** @@ -143,8 +137,6 @@ public class RequestLastFrameNumbersHolder { mLastZslStillFrameNumber = lastZslStillFrameNumber; mLastReprocessFrameNumber = CameraCaptureSession.CaptureCallback.NO_FRAMES_CAPTURED; mRequestId = requestId; - mSequenceCompleted = false; - mInflightCompleted = false; } /** @@ -185,34 +177,5 @@ public class RequestLastFrameNumbersHolder { public int getRequestId() { return mRequestId; } - - /** - * Return whether the capture sequence is completed. - */ - public boolean isSequenceCompleted() { - return mSequenceCompleted; - } - - /** - * Mark the capture sequence as completed. - */ - public void markSequenceCompleted() { - mSequenceCompleted = true; - } - - /** - * Return whether the inflight capture is completed. - */ - public boolean isInflightCompleted() { - return mInflightCompleted; - } - - /** - * Mark the inflight capture as completed. - */ - public void markInflightCompleted() { - mInflightCompleted = true; - } - } diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java index fdd578c419d8..fbc9ac3229c3 100644 --- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java +++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java @@ -109,12 +109,11 @@ public class LegacyCameraDevice implements AutoCloseable { } if (holder == null) { return new CaptureResultExtras(ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE, - ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE, null, - ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE); + ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE, null); } return new CaptureResultExtras(holder.getRequestId(), holder.getSubsequeceId(), /*afTriggerId*/0, /*precaptureTriggerId*/0, holder.getFrameNumber(), - /*partialResultCount*/1, errorStreamId, null, holder.getFrameNumber(), -1, -1); + /*partialResultCount*/1, errorStreamId, null); } /** diff --git a/core/java/android/hardware/soundtrigger/ConversionUtil.java b/core/java/android/hardware/soundtrigger/ConversionUtil.java index 425218a63cf7..c4d123ca4382 100644 --- a/core/java/android/hardware/soundtrigger/ConversionUtil.java +++ b/core/java/android/hardware/soundtrigger/ConversionUtil.java @@ -195,11 +195,14 @@ class ConversionUtil { public static SoundTrigger.RecognitionEvent aidl2apiRecognitionEvent( int modelHandle, RecognitionEvent aidlEvent) { + // The API recognition event doesn't allow for a null audio format, even though it doesn't + // always make sense. We thus replace it with a default. + AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(aidlEvent.audioConfig); return new SoundTrigger.GenericRecognitionEvent( aidlEvent.status, modelHandle, aidlEvent.captureAvailable, aidlEvent.captureSession, aidlEvent.captureDelayMs, aidlEvent.capturePreambleMs, aidlEvent.triggerInData, - aidl2apiAudioFormat(aidlEvent.audioConfig), aidlEvent.data); + audioFormat, aidlEvent.data); } public static SoundTrigger.RecognitionEvent aidl2apiPhraseRecognitionEvent( @@ -210,11 +213,14 @@ class ConversionUtil { for (int i = 0; i < aidlEvent.phraseExtras.length; ++i) { apiExtras[i] = aidl2apiPhraseRecognitionExtra(aidlEvent.phraseExtras[i]); } + // The API recognition event doesn't allow for a null audio format, even though it doesn't + // always make sense. We thus replace it with a default. + AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(aidlEvent.common.audioConfig); return new SoundTrigger.KeyphraseRecognitionEvent(aidlEvent.common.status, modelHandle, aidlEvent.common.captureAvailable, aidlEvent.common.captureSession, aidlEvent.common.captureDelayMs, aidlEvent.common.capturePreambleMs, aidlEvent.common.triggerInData, - aidl2apiAudioFormat(aidlEvent.common.audioConfig), aidlEvent.common.data, + audioFormat, aidlEvent.common.data, apiExtras); } @@ -226,6 +232,14 @@ class ConversionUtil { return apiBuilder.build(); } + // Same as above, but in case of a null input returns a non-null valid output. + public static AudioFormat aidl2apiAudioFormatWithDefault(@Nullable AudioConfig audioConfig) { + if (audioConfig != null) { + return aidl2apiAudioFormat(audioConfig); + } + return new AudioFormat.Builder().build(); + } + public static int aidl2apiEncoding(int aidlFormat) { switch (aidlFormat) { case android.media.audio.common.AudioFormat.PCM diff --git a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java index c1df5b6d2e7e..a2a15b30d578 100644 --- a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java +++ b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java @@ -303,7 +303,7 @@ public class SoundTriggerModule { (SoundTrigger.RecognitionEvent) msg.obj); break; case EVENT_SERVICE_STATE_CHANGE: - listener.onServiceStateChange(msg.arg1); + listener.onServiceStateChange((int) msg.obj); break; case EVENT_SERVICE_DIED: listener.onServiceDied(); diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index 65e772cb5ebb..482d2d2192b8 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -357,6 +357,7 @@ public abstract class NetworkAgent { final NetworkInfo ni = new NetworkInfo(config.legacyType, config.legacyType, config.legacyTypeName, ""); ni.setIsAvailable(true); + ni.setExtraInfo(config.getLegacyExtraInfo()); return ni; } diff --git a/core/java/android/net/NetworkAgentConfig.java b/core/java/android/net/NetworkAgentConfig.java index fee868a93be4..fe1268d79b89 100644 --- a/core/java/android/net/NetworkAgentConfig.java +++ b/core/java/android/net/NetworkAgentConfig.java @@ -185,6 +185,26 @@ public final class NetworkAgentConfig implements Parcelable { return legacyTypeName; } + /** + * The legacy extra info of the agent. The extra info should only be : + * <ul> + * <li>For cellular agents, the APN name.</li> + * <li>For ethernet agents, the interface name.</li> + * </ul> + * @hide + */ + @NonNull + private String mLegacyExtraInfo = ""; + + /** + * The legacy extra info of the agent. + * @hide + */ + @NonNull + public String getLegacyExtraInfo() { + return mLegacyExtraInfo; + } + /** @hide */ public NetworkAgentConfig() { } @@ -201,6 +221,7 @@ public final class NetworkAgentConfig implements Parcelable { skip464xlat = nac.skip464xlat; legacyType = nac.legacyType; legacyTypeName = nac.legacyTypeName; + mLegacyExtraInfo = nac.mLegacyExtraInfo; } } @@ -309,6 +330,18 @@ public final class NetworkAgentConfig implements Parcelable { } /** + * Sets the legacy extra info of the agent. + * @param legacyExtraInfo the legacy extra info. + * @return this builder, to facilitate chaining. + * @hide + */ + @NonNull + public Builder setLegacyExtraInfo(@NonNull String legacyExtraInfo) { + mConfig.mLegacyExtraInfo = legacyExtraInfo; + return this; + } + + /** * Returns the constructed {@link NetworkAgentConfig} object. */ @NonNull @@ -330,14 +363,15 @@ public final class NetworkAgentConfig implements Parcelable { && skip464xlat == that.skip464xlat && legacyType == that.legacyType && Objects.equals(subscriberId, that.subscriberId) - && Objects.equals(legacyTypeName, that.legacyTypeName); + && Objects.equals(legacyTypeName, that.legacyTypeName) + && Objects.equals(mLegacyExtraInfo, that.mLegacyExtraInfo); } @Override public int hashCode() { return Objects.hash(allowBypass, explicitlySelected, acceptUnvalidated, acceptPartialConnectivity, provisioningNotificationDisabled, subscriberId, - skip464xlat, legacyType, legacyTypeName); + skip464xlat, legacyType, legacyTypeName, mLegacyExtraInfo); } @Override @@ -353,6 +387,7 @@ public final class NetworkAgentConfig implements Parcelable { + ", legacyType = " + legacyType + ", hasShownBroken = " + hasShownBroken + ", legacyTypeName = '" + legacyTypeName + '\'' + + ", legacyExtraInfo = '" + mLegacyExtraInfo + '\'' + "}"; } @@ -372,6 +407,7 @@ public final class NetworkAgentConfig implements Parcelable { out.writeInt(skip464xlat ? 1 : 0); out.writeInt(legacyType); out.writeString(legacyTypeName); + out.writeString(mLegacyExtraInfo); } public static final @NonNull Creator<NetworkAgentConfig> CREATOR = @@ -388,6 +424,7 @@ public final class NetworkAgentConfig implements Parcelable { networkAgentConfig.skip464xlat = in.readInt() != 0; networkAgentConfig.legacyType = in.readInt(); networkAgentConfig.legacyTypeName = in.readString(); + networkAgentConfig.mLegacyExtraInfo = in.readString(); return networkAgentConfig; } diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 2d4d9575584d..67c97ae29186 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -3592,10 +3592,9 @@ public class ChooserActivity extends ResolverActivity implements * Only expand direct share area if there is a minimum number of targets. */ private boolean canExpandDirectShare() { - int orientation = getResources().getConfiguration().orientation; - return mChooserListAdapter.getNumServiceTargetsForExpand() > getMaxTargetsPerRow() - && orientation == Configuration.ORIENTATION_PORTRAIT - && !isInMultiWindowMode(); + // Do not enable until we have confirmed more apps are using sharing shortcuts + // Check git history for enablement logic + return false; } public ChooserListAdapter getListAdapter() { diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java index f4fb993fbb93..d6ff7b13c934 100644 --- a/core/java/com/android/internal/app/ChooserListAdapter.java +++ b/core/java/com/android/internal/app/ChooserListAdapter.java @@ -181,6 +181,7 @@ public class ChooserListAdapter extends ResolverListAdapter { ri.icon = 0; } mCallerTargets.add(new DisplayResolveInfo(ii, ri, ii, makePresentationGetter(ri))); + if (mCallerTargets.size() == MAX_SUGGESTED_APP_TARGETS) break; } } } @@ -320,7 +321,7 @@ public class ChooserListAdapter extends ResolverListAdapter { public int getCallerTargetCount() { - return Math.min(mCallerTargets.size(), MAX_SUGGESTED_APP_TARGETS); + return mCallerTargets.size(); } /** @@ -346,8 +347,9 @@ public class ChooserListAdapter extends ResolverListAdapter { } int getAlphaTargetCount() { - int standardCount = mSortedList.size(); - return standardCount > mChooserListCommunicator.getMaxRankedTargets() ? standardCount : 0; + int groupedCount = mSortedList.size(); + int ungroupedCount = mCallerTargets.size() + mDisplayList.size(); + return ungroupedCount > mChooserListCommunicator.getMaxRankedTargets() ? groupedCount : 0; } /** diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java index b1e8ed1f943e..d63ebda5117e 100644 --- a/core/java/com/android/internal/app/ResolverListAdapter.java +++ b/core/java/com/android/internal/app/ResolverListAdapter.java @@ -617,7 +617,8 @@ public class ResolverListAdapter extends BaseAdapter { } } - UserHandle getUserHandle() { + @VisibleForTesting + public UserHandle getUserHandle() { return mResolverListController.getUserHandle(); } diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java index 7c7d9312e2db..075159671b17 100644 --- a/core/java/com/android/internal/widget/ConversationLayout.java +++ b/core/java/com/android/internal/widget/ConversationLayout.java @@ -761,9 +761,13 @@ public class ConversationLayout extends FrameLayout // group : mExpandedGroupMessagePadding; + int iconPadding = mIsOneToOne || mIsCollapsed + ? mConversationIconTopPadding + : mConversationIconTopPaddingExpandedGroup; + mConversationIconContainer.setPaddingRelative( mConversationIconContainer.getPaddingStart(), - mConversationIconTopPadding, + iconPadding, mConversationIconContainer.getPaddingEnd(), mConversationIconContainer.getPaddingBottom()); diff --git a/core/res/res/layout/notification_template_material_conversation.xml b/core/res/res/layout/notification_template_material_conversation.xml index d3857941969b..139185f98b69 100644 --- a/core/res/res/layout/notification_template_material_conversation.xml +++ b/core/res/res/layout/notification_template_material_conversation.xml @@ -148,7 +148,6 @@ android:layout_weight="1" /> - <TextView android:id="@+id/app_name_divider" android:layout_width="wrap_content" @@ -174,6 +173,7 @@ android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin" android:paddingTop="1sp" android:singleLine="true" + android:visibility="gone" /> <TextView @@ -192,7 +192,7 @@ <DateTimeView android:id="@+id/time" - android:textAppearance="@style/TextAppearance.Material.Notification.Time" + android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index b79c9e804f89..0e11d49c93e5 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -4313,10 +4313,6 @@ notifications until they target R --> <string-array name="config_notificationMsgPkgsAllowedAsConvos" translatable="false"/> - <!-- Contains a blacklist of apps that should not get pre-installed carrier app permission - grants, even if the UICC claims that the app should be privileged. See b/138150105 --> - <string-array name="config_restrictedPreinstalledCarrierApps" translatable="false"/> - <!-- Sharesheet: define a max number of targets per application for new shortcuts-based direct share introduced in Q --> <integer name="config_maxShortcutTargetsPerApp">3</integer> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 4ee919289f28..ebaf85c64a14 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -734,7 +734,7 @@ <dimen name="conversation_icon_container_top_padding">12dp</dimen> <!-- The top padding of the conversation icon container when the avatar is small--> - <dimen name="conversation_icon_container_top_padding_small_avatar">17.5dp</dimen> + <dimen name="conversation_icon_container_top_padding_small_avatar">9dp</dimen> <!-- The padding of the conversation header when expanded. This is calculated from the expand button size + notification_content_margin_end --> <dimen name="conversation_header_expanded_padding_end">38dp</dimen> diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml index e9ac679ec39c..ef019ba92769 100644 --- a/core/res/res/values/styles_device_defaults.xml +++ b/core/res/res/values/styles_device_defaults.xml @@ -296,9 +296,12 @@ easier. <style name="TextAppearance.DeviceDefault.Notification.Info" parent="TextAppearance.Material.Notification.Info"> <item name="fontFamily">@string/config_bodyFontFamily</item> </style> + <style name="TextAppearance.DeviceDefault.Notification.Time" parent="TextAppearance.Material.Notification.Time"> + <item name="fontFamily">@string/config_bodyFontFamily</item> + </style> <style name="TextAppearance.DeviceDefault.Notification.Conversation.AppName" - parent="@*android:style/TextAppearance.DeviceDefault.Notification.Title"> - <item name="android:textSize">16sp</item> + parent="TextAppearance.Material.Notification.Conversation.AppName"> + <item name="fontFamily">@string/config_headlineFontFamilyMedium</item> </style> <style name="TextAppearance.DeviceDefault.Widget" parent="TextAppearance.Material.Widget"> <item name="fontFamily">@string/config_bodyFontFamily</item> diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml index 2415837cf826..67536fde9b0b 100644 --- a/core/res/res/values/styles_material.xml +++ b/core/res/res/values/styles_material.xml @@ -491,6 +491,10 @@ please see styles_device_defaults.xml. <item name="textColor">#66000000</item> </style> + <style name="TextAppearance.Material.Notification.Conversation.AppName" parent="TextAppearance.Material.Notification.Title"> + <item name="android:textSize">16sp</item> + </style> + <style name="TextAppearance.Material.ListItem" parent="TextAppearance.Material.Subhead" /> <style name="TextAppearance.Material.ListItemSecondary" parent="TextAppearance.Material.Body1" /> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 23ae1e7d271e..c56c78a0b6a1 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3827,7 +3827,6 @@ <java-symbol type="string" name="config_defaultSupervisionProfileOwnerComponent" /> <java-symbol type="bool" name="config_inflateSignalStrength" /> - <java-symbol type="array" name="config_restrictedPreinstalledCarrierApps" /> <java-symbol type="drawable" name="android_logotype" /> <java-symbol type="layout" name="platlogo_layout" /> @@ -3956,6 +3955,13 @@ <java-symbol type="id" name="conversation_unread_count" /> <java-symbol type="string" name="unread_convo_overflow" /> <java-symbol type="style" name="TextAppearance.DeviceDefault.Notification.Conversation.AppName" /> + <java-symbol type="drawable" name="conversation_badge_background" /> + <java-symbol type="drawable" name="conversation_badge_ring" /> + <java-symbol type="color" name="conversation_important_highlight" /> + <java-symbol type="dimen" name="importance_ring_stroke_width" /> + <java-symbol type="dimen" name="importance_ring_anim_max_stroke_width" /> + <java-symbol type="dimen" name="importance_ring_size" /> + <java-symbol type="dimen" name="conversation_icon_size_badged" /> <!-- Intent resolver and share sheet --> <java-symbol type="string" name="resolver_personal_tab" /> diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java index 547176855f32..49de7c80057f 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java +++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java @@ -21,6 +21,7 @@ import static androidx.test.espresso.action.ViewActions.click; import static androidx.test.espresso.action.ViewActions.swipeUp; import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist; import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.ViewMatchers.hasSibling; import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; import static androidx.test.espresso.matcher.ViewMatchers.withId; import static androidx.test.espresso.matcher.ViewMatchers.withText; @@ -299,9 +300,8 @@ public class ChooserActivityTest { public void fourOptionsStackedIntoOneTarget() throws InterruptedException { Intent sendIntent = createSendTextIntent(); - // create 12 unique app targets to ensure the app ranking row can be filled, otherwise - // targets will not stack - List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(12); + // create just enough targets to ensure the a-z list should be shown + List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(1); // next create 4 targets in a single app that should be stacked into a single target String packageName = "xxx.yyy"; @@ -328,8 +328,8 @@ public class ChooserActivityTest { .launchActivity(Intent.createChooser(sendIntent, null)); waitForIdle(); - // expect 12 unique targets + 1 group + 4 ranked app targets - assertThat(activity.getAdapter().getCount(), is(17)); + // expect 1 unique targets + 1 group + 4 ranked app targets + assertThat(activity.getAdapter().getCount(), is(6)); ResolveInfo[] chosen = new ResolveInfo[1]; sOverrides.onSafelyStartCallback = targetInfo -> { @@ -337,7 +337,7 @@ public class ChooserActivityTest { return true; }; - onView(withText(appName)).perform(click()); + onView(allOf(withText(appName), hasSibling(withText("")))).perform(click()); waitForIdle(); // clicking will launch a dialog to choose the activity within the app diff --git a/media/java/android/media/soundtrigger_middleware/RecognitionEvent.aidl b/media/java/android/media/soundtrigger_middleware/RecognitionEvent.aidl index de4d060ce484..a237ec1aa3b3 100644 --- a/media/java/android/media/soundtrigger_middleware/RecognitionEvent.aidl +++ b/media/java/android/media/soundtrigger_middleware/RecognitionEvent.aidl @@ -43,9 +43,9 @@ parcelable RecognitionEvent { boolean triggerInData; /** * Audio format of either the trigger in event data or to use for capture of the rest of the - * utterance. + * utterance. May be null when no audio is available for this event type. */ - AudioConfig audioConfig; + @nullable AudioConfig audioConfig; /** Additional data. */ byte[] data; } diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java index 8f919c3d86ca..132922a59fc1 100644 --- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java +++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java @@ -520,9 +520,11 @@ public class ExternalStorageProvider extends FileSystemProvider { final RootInfo root = resolvedDocId.first; File child = resolvedDocId.second; + final File rootFile = root.visiblePath != null ? root.visiblePath + : root.path; final File parent = TextUtils.isEmpty(parentDocId) - ? root.path - : getFileForDocId(parentDocId); + ? rootFile + : getFileForDocId(parentDocId); return new Path(parentDocId == null ? root.rootId : null, findDocumentPath(parent, child)); } diff --git a/packages/SettingsLib/OWNERS b/packages/SettingsLib/OWNERS index a28ba8584054..d7bd6a49d75b 100644 --- a/packages/SettingsLib/OWNERS +++ b/packages/SettingsLib/OWNERS @@ -3,6 +3,7 @@ dsandler@android.com edgarwang@google.com emilychuang@google.com evanlaird@google.com +juliacr@google.com leifhendrik@google.com rafftsai@google.com tmfang@google.com diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java b/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java index d5f1ece5f83f..549bc8a455cf 100644 --- a/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java +++ b/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java @@ -86,7 +86,7 @@ public class ConversationIconFactory extends BaseIconFactory { /** * Returns the conversation info drawable */ - private Drawable getBaseIconDrawable(ShortcutInfo shortcutInfo) { + public Drawable getBaseIconDrawable(ShortcutInfo shortcutInfo) { return mLauncherApps.getShortcutIconDrawable(shortcutInfo, mFillResIconDpi); } @@ -94,7 +94,7 @@ public class ConversationIconFactory extends BaseIconFactory { * Get the {@link Drawable} that represents the app icon, badged with the work profile icon * if appropriate. */ - private Drawable getAppBadge(String packageName, int userId) { + public Drawable getAppBadge(String packageName, int userId) { Drawable badge = null; try { final ApplicationInfo appInfo = mPackageManager.getApplicationInfoAsUser( diff --git a/packages/SystemUI/res/layout/notification_conversation_info.xml b/packages/SystemUI/res/layout/notification_conversation_info.xml index 49d525fc189a..3d36f7a2ecfe 100644 --- a/packages/SystemUI/res/layout/notification_conversation_info.xml +++ b/packages/SystemUI/res/layout/notification_conversation_info.xml @@ -34,7 +34,7 @@ android:layout_height="wrap_content" android:gravity="center_vertical" android:clipChildren="false" - android:paddingTop="8dp" + android:paddingTop="11dp" android:clipToPadding="true"> <ImageView android:id="@+id/conversation_icon" diff --git a/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml b/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml index bf2eac3c8ff3..3f0e514a9af2 100644 --- a/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml +++ b/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml @@ -38,11 +38,61 @@ android:background="@drawable/rounded_bg_full" > + <FrameLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:clipChildren="false" + android:clipToPadding="false" + android:padding="12dp" + android:layout_gravity="center_horizontal" + > + + <!-- Big icon: 52x52, 12dp padding left + top, 16dp padding right --> <ImageView android:id="@+id/conversation_icon" - android:layout_width="@dimen/notification_guts_conversation_icon_size" - android:layout_height="@dimen/notification_guts_conversation_icon_size" - android:layout_gravity="center_horizontal" /> + android:layout_width="@*android:dimen/conversation_avatar_size" + android:layout_height="@*android:dimen/conversation_avatar_size" + android:scaleType="centerCrop" + android:importantForAccessibility="no" + /> + + <FrameLayout + android:id="@+id/conversation_icon_badge" + android:layout_width="@*android:dimen/conversation_icon_size_badged" + android:layout_height="@*android:dimen/conversation_icon_size_badged" + android:layout_marginLeft="@*android:dimen/conversation_badge_side_margin" + android:layout_marginTop="@*android:dimen/conversation_badge_side_margin" + android:clipChildren="false" + android:clipToPadding="false" + > + <ImageView + android:id="@+id/conversation_icon_badge_bg" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_gravity="center" + android:src="@*android:drawable/conversation_badge_background" + android:forceHasOverlappingRendering="false" + /> + <ImageView + android:id="@+id/icon" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_margin="4dp" + android:layout_gravity="center" + android:forceHasOverlappingRendering="false" + /> + <ImageView + android:id="@+id/conversation_icon_badge_ring" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:src="@*android:drawable/conversation_badge_ring" + android:forceHasOverlappingRendering="false" + android:clipToPadding="false" + android:scaleType="center" + /> + </FrameLayout> + </FrameLayout> <TextView android:id="@+id/title" diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java index ccb506de6d8b..0218cd237037 100644 --- a/packages/SystemUI/src/com/android/systemui/Prefs.java +++ b/packages/SystemUI/src/com/android/systemui/Prefs.java @@ -124,7 +124,7 @@ public final class Prefs { String HAS_SEEN_BUBBLES_MANAGE_EDUCATION = "HasSeenBubblesManageOnboarding"; String CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT = "ControlsStructureSwipeTooltipCount"; /** Tracks whether the user has seen the onboarding screen for priority conversations */ - String HAS_SEEN_PRIORITY_ONBOARDING = "HaveShownPriorityOnboarding"; + String HAS_SEEN_PRIORITY_ONBOARDING = "HasUserSeenPriorityOnboarding"; } public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) { diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt index 2f521ea39242..de0af16bc2fa 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt @@ -34,7 +34,6 @@ class MediaDeviceManager @Inject constructor( private val context: Context, private val localMediaManagerFactory: LocalMediaManagerFactory, private val mr2manager: MediaRouter2Manager, - private val featureFlag: MediaFeatureFlag, @Main private val fgExecutor: Executor, private val mediaDataManager: MediaDataManager ) : MediaDataManager.Listener { @@ -56,20 +55,19 @@ class MediaDeviceManager @Inject constructor( fun removeListener(listener: Listener) = listeners.remove(listener) override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) { - if (featureFlag.enabled) { - if (oldKey != null && oldKey != key) { - val oldToken = entries.remove(oldKey) - oldToken?.stop() - } - var tok = entries[key] - if (tok == null && data.token != null) { - val controller = MediaController(context, data.token!!) - tok = Token(key, controller, localMediaManagerFactory.create(data.packageName)) - entries[key] = tok - tok.start() + if (oldKey != null && oldKey != key) { + val oldEntry = entries.remove(oldKey) + oldEntry?.stop() + } + var entry = entries[key] + if (entry == null || entry?.token != data.token) { + entry?.stop() + val controller = data.token?.let { + MediaController(context, it) } - } else { - onMediaDataRemoved(key) + entry = Token(key, controller, localMediaManagerFactory.create(data.packageName)) + entries[key] = entry + entry.start() } } @@ -100,9 +98,11 @@ class MediaDeviceManager @Inject constructor( private inner class Token( val key: String, - val controller: MediaController, + val controller: MediaController?, val localMediaManager: LocalMediaManager ) : LocalMediaManager.DeviceCallback { + val token + get() = controller?.sessionToken private var started = false private var current: MediaDevice? = null set(value) { @@ -132,10 +132,14 @@ class MediaDeviceManager @Inject constructor( } private fun updateCurrent() { val device = localMediaManager.getCurrentConnectedDevice() - val route = mr2manager.getRoutingSessionForMediaController(controller) - // If we get a null route, then don't trust the device. Just set to null to disable the - // output switcher chip. - current = if (route != null) device else null + controller?.let { + val route = mr2manager.getRoutingSessionForMediaController(it) + // If we get a null route, then don't trust the device. Just set to null to disable the + // output switcher chip. + current = if (route != null) device else null + } ?: run { + current = device + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java index c6f144aa57a1..b93e07e65c73 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java @@ -504,8 +504,18 @@ public class PipTaskOrganizer extends TaskOrganizer implements // this could happen if rotation finishes before the animation mLastReportedBounds.set(destinationBoundsOut); scheduleFinishResizePip(mLastReportedBounds); - } else if (!mLastReportedBounds.isEmpty()) { - destinationBoundsOut.set(mLastReportedBounds); + } else { + // There could be an animation on-going. If there is one on-going, last-reported + // bounds isn't yet updated. We'll use the animator's bounds instead. + if (animator != null && animator.isRunning()) { + if (!animator.getDestinationBounds().isEmpty()) { + destinationBoundsOut.set(animator.getDestinationBounds()); + } + } else { + if (!mLastReportedBounds.isEmpty()) { + destinationBoundsOut.set(mLastReportedBounds); + } + } } return; } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java index a624479fa63c..55994594d32f 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java @@ -208,6 +208,7 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset private Animator mScreenshotAnimation; private Runnable mOnCompleteRunnable; private Animator mDismissAnimation; + private SavedImageData mImageData; private boolean mInDarkMode = false; private boolean mDirectionLTR = true; private boolean mOrientationPortrait = true; @@ -226,6 +227,9 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset switch (msg.what) { case MESSAGE_CORNER_TIMEOUT: mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_INTERACTION_TIMEOUT); + if (mImageData != null) { + mNotificationsController.showSilentScreenshotNotification(mImageData); + } GlobalScreenshot.this.dismissScreenshot("timeout", false); mOnCompleteRunnable.run(); break; @@ -396,6 +400,9 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset mDismissButton = mScreenshotLayout.findViewById(R.id.global_screenshot_dismiss_button); mDismissButton.setOnClickListener(view -> { mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_EXPLICIT_DISMISSAL); + if (mImageData != null) { + mNotificationsController.showSilentScreenshotNotification(mImageData); + } dismissScreenshot("dismiss_button", false); mOnCompleteRunnable.run(); }); @@ -436,6 +443,10 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset }); } + mImageData = null; // make sure we clear the current stored data + mNotificationsController.reset(); + mNotificationsController.setImage(mScreenBitmap); + mSaveInBgTask = new SaveImageInBackgroundTask(mContext, data); mSaveInBgTask.execute(); } @@ -643,6 +654,7 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset */ private void showUiOnActionsReady(SavedImageData imageData) { logSuccessOnActionsReady(imageData); + mImageData = imageData; AccessibilityManager accessibilityManager = (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java index fbcd6ba0ff47..46fe7f4630bd 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationsController.java @@ -226,6 +226,66 @@ public class ScreenshotNotificationsController { } /** + * Shows a silent notification with the saved screenshot and actions that can be taken with it. + * + * @param actionData SavedImageData struct with image URI and actions + */ + public void showSilentScreenshotNotification( + GlobalScreenshot.SavedImageData actionData) { + mNotificationBuilder.addAction(actionData.shareAction); + mNotificationBuilder.addAction(actionData.editAction); + mNotificationBuilder.addAction(actionData.deleteAction); + for (Notification.Action smartAction : actionData.smartActions) { + mNotificationBuilder.addAction(smartAction); + } + + // Create the intent to show the screenshot in gallery + Intent launchIntent = new Intent(Intent.ACTION_VIEW); + launchIntent.setDataAndType(actionData.uri, "image/png"); + launchIntent.setFlags( + Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION); + + final long now = System.currentTimeMillis(); + + // Update the text and the icon for the existing notification + mPublicNotificationBuilder + .setContentTitle(mResources.getString(R.string.screenshot_saved_title)) + .setContentText(mResources.getString(R.string.screenshot_saved_text)) + .setContentIntent(PendingIntent.getActivity(mContext, 0, launchIntent, 0)) + .setSmallIcon(R.drawable.stat_notify_image) + .setCategory(Notification.CATEGORY_PROGRESS) + .setWhen(now) + .setShowWhen(true) + .setAutoCancel(true) + .setColor(mContext.getColor( + com.android.internal.R.color.system_notification_accent_color)) + .setGroup("silent") + .setGroupAlertBehavior(Notification.GROUP_ALERT_SUMMARY); + mNotificationBuilder + .setContentTitle(mResources.getString(R.string.screenshot_saved_title)) + .setContentText(mResources.getString(R.string.screenshot_saved_text)) + .setContentIntent(PendingIntent.getActivity(mContext, 0, launchIntent, 0)) + .setSmallIcon(R.drawable.stat_notify_image) + .setCategory(Notification.CATEGORY_PROGRESS) + .setWhen(now) + .setShowWhen(true) + .setAutoCancel(true) + .setColor(mContext.getColor( + com.android.internal.R.color.system_notification_accent_color)) + .setPublicVersion(mPublicNotificationBuilder.build()) + .setStyle(mNotificationStyle) + .setFlag(Notification.FLAG_NO_CLEAR, false) + .setGroup("silent") + .setGroupAlertBehavior(Notification.GROUP_ALERT_SUMMARY); + + SystemUI.overrideNotificationAppName(mContext, mPublicNotificationBuilder, true); + SystemUI.overrideNotificationAppName(mContext, mNotificationBuilder, true); + + mNotificationManager.notify(SystemMessageProto.SystemMessage.NOTE_GLOBAL_SCREENSHOT, + mNotificationBuilder.build()); + } + + /** * Sends a notification that the screenshot capture has failed. */ public void notifyScreenshotError(int msgResId) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java index f4afb91396b5..bee2f7002823 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java @@ -44,6 +44,7 @@ import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager; import android.os.Handler; import android.os.RemoteException; +import android.os.UserHandle; import android.provider.Settings; import android.service.notification.StatusBarNotification; import android.text.TextUtils; @@ -540,7 +541,9 @@ public class NotificationConversationInfo extends LinearLayout implements .setView(onboardingView) .setIgnoresDnd(ignoreDnd) .setShowsAsBubble(showAsBubble) - .setIcon(((ImageView) findViewById(R.id.conversation_icon)).getDrawable()) + .setIcon(mIconFactory.getBaseIconDrawable(mShortcutInfo)) + .setBadge(mIconFactory.getAppBadge( + mPackageName, UserHandle.getUserId(mSbn.getUid()))) .setOnSettingsClick(mOnConversationSettingsClickListener) .build(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt index c88f0bdc2acb..fab367df8fde 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt @@ -16,41 +16,57 @@ package com.android.systemui.statusbar.notification.row +import android.animation.Animator +import android.animation.AnimatorListenerAdapter +import android.animation.AnimatorSet +import android.animation.ValueAnimator import android.app.Dialog import android.content.Context import android.graphics.Color import android.graphics.PixelFormat import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable +import android.graphics.drawable.GradientDrawable import android.text.SpannableStringBuilder import android.text.style.BulletSpan import android.view.Gravity import android.view.View +import android.view.ViewGroup import android.view.ViewGroup.LayoutParams.MATCH_PARENT import android.view.ViewGroup.LayoutParams.WRAP_CONTENT import android.view.Window import android.view.WindowInsets.Type.statusBars import android.view.WindowManager +import android.view.animation.Interpolator +import android.view.animation.PathInterpolator import android.widget.ImageView import android.widget.TextView +import com.android.systemui.Interpolators.LINEAR_OUT_SLOW_IN import com.android.systemui.Prefs import com.android.systemui.R import com.android.systemui.statusbar.notification.row.NotificationConversationInfo.OnConversationSettingsClickListener import javax.inject.Inject + /** * Controller to handle presenting the priority conversations onboarding dialog */ class PriorityOnboardingDialogController @Inject constructor( - val view: View, - val context: Context, - val ignoresDnd: Boolean, - val showsAsBubble: Boolean, - val icon : Drawable, - val onConversationSettingsClickListener : OnConversationSettingsClickListener + val view: View, + val context: Context, + private val ignoresDnd: Boolean, + private val showsAsBubble: Boolean, + val icon : Drawable, + private val onConversationSettingsClickListener : OnConversationSettingsClickListener, + val badge : Drawable ) { private lateinit var dialog: Dialog + private val OVERSHOOT: Interpolator = PathInterpolator(0.4f, 0f, 0.2f, 1.4f) + private val IMPORTANCE_ANIM_DELAY = 150L + private val IMPORTANCE_ANIM_GROW_DURATION = 250L + private val IMPORTANCE_ANIM_SHRINK_DURATION = 200L + private val IMPORTANCE_ANIM_SHRINK_DELAY = 25L fun init() { initDialog() @@ -81,6 +97,7 @@ class PriorityOnboardingDialogController @Inject constructor( private lateinit var icon: Drawable private lateinit var onConversationSettingsClickListener : OnConversationSettingsClickListener + private lateinit var badge : Drawable fun setView(v: View): Builder { view = v @@ -106,6 +123,10 @@ class PriorityOnboardingDialogController @Inject constructor( icon = draw return this } + fun setBadge(badge : Drawable) : Builder { + this.badge = badge + return this + } fun setOnSettingsClick(onClick : OnConversationSettingsClickListener) : Builder { onConversationSettingsClickListener = onClick @@ -115,7 +136,7 @@ class PriorityOnboardingDialogController @Inject constructor( fun build(): PriorityOnboardingDialogController { val controller = PriorityOnboardingDialogController( view, context, ignoresDnd, showAsBubble, icon, - onConversationSettingsClickListener) + onConversationSettingsClickListener, badge) return controller } } @@ -143,6 +164,65 @@ class PriorityOnboardingDialogController @Inject constructor( } findViewById<ImageView>(R.id.conversation_icon)?.setImageDrawable(icon) + findViewById<ImageView>(R.id.icon)?.setImageDrawable(badge) + val mImportanceRingView = findViewById<ImageView>(R.id.conversation_icon_badge_ring) + val conversationIconBadgeBg = findViewById<ImageView>(R.id.conversation_icon_badge_bg) + + val ring: GradientDrawable = mImportanceRingView.drawable as GradientDrawable + ring.mutate() + val bg = conversationIconBadgeBg.drawable as GradientDrawable + bg.mutate() + val ringColor = context.getResources() + .getColor(com.android.internal.R.color.conversation_important_highlight) + val standardThickness = context.resources.getDimensionPixelSize( + com.android.internal.R.dimen.importance_ring_stroke_width) + val largeThickness = context.resources.getDimensionPixelSize( + com.android.internal.R.dimen.importance_ring_anim_max_stroke_width) + val standardSize = context.resources.getDimensionPixelSize( + com.android.internal.R.dimen.importance_ring_size) + val baseSize = standardSize - standardThickness * 2 + val largeSize = baseSize + largeThickness * 2 + val bgSize = context.resources.getDimensionPixelSize( + com.android.internal.R.dimen.conversation_icon_size_badged) + + val animatorUpdateListener: ValueAnimator.AnimatorUpdateListener + = ValueAnimator.AnimatorUpdateListener { animation -> + val strokeWidth = animation.animatedValue as Int + ring.setStroke(strokeWidth, ringColor) + val newSize = baseSize + strokeWidth * 2 + ring.setSize(newSize, newSize) + mImportanceRingView.invalidate() + } + + val growAnimation: ValueAnimator = ValueAnimator.ofInt(0, largeThickness) + growAnimation.interpolator = LINEAR_OUT_SLOW_IN + growAnimation.duration = IMPORTANCE_ANIM_GROW_DURATION + growAnimation.addUpdateListener(animatorUpdateListener) + + val shrinkAnimation: ValueAnimator + = ValueAnimator.ofInt(largeThickness, standardThickness) + shrinkAnimation.duration = IMPORTANCE_ANIM_SHRINK_DURATION + shrinkAnimation.startDelay = IMPORTANCE_ANIM_SHRINK_DELAY + shrinkAnimation.interpolator = OVERSHOOT + shrinkAnimation.addUpdateListener(animatorUpdateListener) + shrinkAnimation.addListener(object : AnimatorListenerAdapter() { + override fun onAnimationStart(animation: Animator?) { + // Shrink the badge bg so that it doesn't peek behind the animation + bg.setSize(baseSize, baseSize); + conversationIconBadgeBg.invalidate(); + } + + override fun onAnimationEnd(animation: Animator?) { + // Reset bg back to normal size + bg.setSize(bgSize, bgSize); + conversationIconBadgeBg.invalidate(); + + } + }) + + val anims = AnimatorSet() + anims.startDelay = IMPORTANCE_ANIM_DELAY + anims.playSequentially(growAnimation, shrinkAnimation) val gapWidth = dialog.context.getResources().getDimensionPixelSize( R.dimen.conversation_onboarding_bullet_gap_width) @@ -180,6 +260,7 @@ class PriorityOnboardingDialogController @Inject constructor( height = WRAP_CONTENT } } + anims.start() } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index b11ed23c3aeb..684bf1958154 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -6539,7 +6539,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd return row.canViewBeDismissed(); } if (v instanceof PeopleHubView) { - return true; + return ((PeopleHubView) v).getCanSwipe(); } return false; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt index a1d898fb84b0..8f77a1d776e4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt @@ -72,7 +72,7 @@ class PeopleHubView(context: Context, attrs: AttributeSet) : } } - var canSwipe: Boolean = true + var canSwipe: Boolean = false set(value) { if (field != value) { if (field) { diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt b/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt index 318a6d727e5c..016f4de724b6 100644 --- a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt +++ b/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt @@ -644,6 +644,12 @@ class PhysicsAnimator<T> private constructor (target: T) { it.onInternalAnimationEnd( property, canceled, value, velocity, anim is FlingAnimation) } + if (springAnimations[property] == anim) { + springAnimations.remove(property) + } + if (flingAnimations[property] == anim) { + flingAnimations.remove(property) + } } return anim } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt index 3a3140f2ff53..6fcf6e37572b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt @@ -51,6 +51,7 @@ import org.mockito.Mockito.`when` as whenever import org.mockito.junit.MockitoJUnit private const val KEY = "TEST_KEY" +private const val KEY_OLD = "TEST_KEY_OLD" private const val PACKAGE = "PKG" private const val SESSION_KEY = "SESSION_KEY" private const val SESSION_ARTIST = "SESSION_ARTIST" @@ -69,7 +70,6 @@ public class MediaDeviceManagerTest : SysuiTestCase() { @Mock private lateinit var lmmFactory: LocalMediaManagerFactory @Mock private lateinit var lmm: LocalMediaManager @Mock private lateinit var mr2: MediaRouter2Manager - @Mock private lateinit var featureFlag: MediaFeatureFlag private lateinit var fakeExecutor: FakeExecutor @Mock private lateinit var listener: MediaDeviceManager.Listener @Mock private lateinit var device: MediaDevice @@ -85,8 +85,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { @Before fun setUp() { fakeExecutor = FakeExecutor(FakeSystemClock()) - manager = MediaDeviceManager(context, lmmFactory, mr2, featureFlag, fakeExecutor, - mediaDataManager) + manager = MediaDeviceManager(context, lmmFactory, mr2, fakeExecutor, mediaDataManager) manager.addListener(listener) // Configure mocks. @@ -95,7 +94,6 @@ public class MediaDeviceManagerTest : SysuiTestCase() { whenever(lmmFactory.create(PACKAGE)).thenReturn(lmm) whenever(lmm.getCurrentConnectedDevice()).thenReturn(device) whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(route) - whenever(featureFlag.enabled).thenReturn(true) // Create a media sesssion and notification for testing. metadataBuilder = MediaMetadata.Builder().apply { @@ -132,23 +130,74 @@ public class MediaDeviceManagerTest : SysuiTestCase() { } @Test - fun addNotification() { + fun loadMediaData() { manager.onMediaDataLoaded(KEY, null, mediaData) verify(lmmFactory).create(PACKAGE) } @Test - fun featureDisabled() { - whenever(featureFlag.enabled).thenReturn(false) + fun loadAndRemoveMediaData() { manager.onMediaDataLoaded(KEY, null, mediaData) - verify(lmmFactory, never()).create(PACKAGE) + manager.onMediaDataRemoved(KEY) + verify(lmm).unregisterCallback(any()) } @Test - fun addAndRemoveNotification() { - manager.onMediaDataLoaded(KEY, null, mediaData) - manager.onMediaDataRemoved(KEY) + fun loadMediaDataWithNullToken() { + manager.onMediaDataLoaded(KEY, null, mediaData.copy(token = null)) + fakeExecutor.runAllReady() + val data = captureDeviceData(KEY) + assertThat(data.enabled).isTrue() + assertThat(data.name).isEqualTo(DEVICE_NAME) + } + + @Test + fun loadWithNewKey() { + // GIVEN that media data has been loaded with an old key + manager.onMediaDataLoaded(KEY_OLD, null, mediaData) + reset(listener) + // WHEN data is loaded with a new key + manager.onMediaDataLoaded(KEY, KEY_OLD, mediaData) + // THEN the listener for the old key should removed. verify(lmm).unregisterCallback(any()) + // AND a new device event emitted + val data = captureDeviceData(KEY) + assertThat(data.enabled).isTrue() + assertThat(data.name).isEqualTo(DEVICE_NAME) + } + + @Test + fun newKeySameAsOldKey() { + // GIVEN that media data has been loaded + manager.onMediaDataLoaded(KEY, null, mediaData) + reset(listener) + // WHEN the new key is the same as the old key + manager.onMediaDataLoaded(KEY, KEY, mediaData) + // THEN no event should be emitted + verify(listener, never()).onMediaDeviceChanged(eq(KEY), any()) + } + + @Test + fun unknownOldKey() { + manager.onMediaDataLoaded(KEY, "unknown", mediaData) + verify(listener).onMediaDeviceChanged(eq(KEY), any()) + } + + @Test + fun updateToSessionTokenWithNullRoute() { + // GIVEN that media data has been loaded with a null token + manager.onMediaDataLoaded(KEY, null, mediaData.copy(token = null)) + // WHEN media data is loaded with a different token + // AND that token results in a null route + reset(listener) + whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null) + manager.onMediaDataLoaded(KEY, null, mediaData) + // THEN the device should be disabled + fakeExecutor.runAllReady() + val data = captureDeviceData(KEY) + assertThat(data.enabled).isFalse() + assertThat(data.name).isNull() + assertThat(data.icon).isNull() } @Test @@ -164,6 +213,15 @@ public class MediaDeviceManagerTest : SysuiTestCase() { } @Test + fun removeListener() { + // WHEN a listener is removed + manager.removeListener(listener) + // THEN it doesn't receive device events + manager.onMediaDataLoaded(KEY, null, mediaData) + verify(listener, never()).onMediaDeviceChanged(eq(KEY), any()) + } + + @Test fun deviceListUpdate() { manager.onMediaDataLoaded(KEY, null, mediaData) val deviceCallback = captureCallback() diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java index d03deda37fdf..593d04a06b93 100644 --- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java +++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java @@ -24,8 +24,10 @@ import android.app.Notification.Action; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; import android.net.NetworkCapabilities; @@ -253,6 +255,14 @@ public class TetheringNotificationUpdater { } @VisibleForTesting + static String getSettingsPackageName(@NonNull final PackageManager pm) { + final Intent settingsIntent = new Intent(Settings.ACTION_SETTINGS); + final ComponentName settingsComponent = settingsIntent.resolveActivity(pm); + return settingsComponent != null + ? settingsComponent.getPackageName() : "com.android.settings"; + } + + @VisibleForTesting void notifyTetheringDisabledByRestriction() { final Resources res = getResourcesForSubId(mContext, mActiveDataSubId); final String title = res.getString(R.string.disable_tether_notification_title); @@ -262,8 +272,9 @@ public class TetheringNotificationUpdater { final PendingIntent pi = PendingIntent.getActivity( mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */), 0 /* requestCode */, - new Intent(Settings.ACTION_TETHER_SETTINGS), - Intent.FLAG_ACTIVITY_NEW_TASK, + new Intent(Settings.ACTION_TETHER_SETTINGS) + .setPackage(getSettingsPackageName(mContext.getPackageManager())), + Intent.FLAG_ACTIVITY_NEW_TASK | PendingIntent.FLAG_IMMUTABLE, null /* options */); showNotification(R.drawable.stat_sys_tether_general, title, message, @@ -284,7 +295,7 @@ public class TetheringNotificationUpdater { mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */), 0 /* requestCode */, intent, - 0 /* flags */); + PendingIntent.FLAG_IMMUTABLE); final Action action = new Action.Builder(NO_ICON_ID, disableButton, pi).build(); showNotification(R.drawable.stat_sys_tether_general, title, message, @@ -305,8 +316,9 @@ public class TetheringNotificationUpdater { final PendingIntent pi = PendingIntent.getActivity( mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */), 0 /* requestCode */, - new Intent(Settings.ACTION_TETHER_SETTINGS), - Intent.FLAG_ACTIVITY_NEW_TASK, + new Intent(Settings.ACTION_TETHER_SETTINGS) + .setPackage(getSettingsPackageName(mContext.getPackageManager())), + Intent.FLAG_ACTIVITY_NEW_TASK | PendingIntent.FLAG_IMMUTABLE, null /* options */); showNotification(R.drawable.stat_sys_tether_general, title, message, diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt index 7d5471f7703d..4b6bbac051e0 100644 --- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt +++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt @@ -19,6 +19,10 @@ package com.android.networkstack.tethering import android.app.Notification import android.app.NotificationManager import android.content.Context +import android.content.pm.ActivityInfo +import android.content.pm.ApplicationInfo +import android.content.pm.PackageManager +import android.content.pm.ResolveInfo import android.content.res.Resources import android.net.ConnectivityManager.TETHERING_WIFI import android.os.Handler @@ -51,6 +55,7 @@ import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.eq import org.mockito.Mock import org.mockito.Mockito.doReturn +import org.mockito.Mockito.mock import org.mockito.Mockito.never import org.mockito.Mockito.reset import org.mockito.Mockito.times @@ -351,4 +356,26 @@ class TetheringNotificationUpdaterTest { notificationUpdater.onUpstreamCapabilitiesChanged(ROAMING_CAPABILITIES) verifyNotificationCancelled(listOf(NO_UPSTREAM_NOTIFICATION_ID, ROAMING_NOTIFICATION_ID)) } + + @Test + fun testGetSettingsPackageName() { + val defaultSettingsPackageName = "com.android.settings" + val testSettingsPackageName = "com.android.test.settings" + val pm = mock(PackageManager::class.java) + doReturn(null).`when`(pm).resolveActivity(any(), anyInt()) + assertEquals(defaultSettingsPackageName, + TetheringNotificationUpdater.getSettingsPackageName(pm)) + + val resolveInfo = ResolveInfo().apply { + activityInfo = ActivityInfo().apply { + name = "test" + applicationInfo = ApplicationInfo().apply { + packageName = testSettingsPackageName + } + } + } + doReturn(resolveInfo).`when`(pm).resolveActivity(any(), anyInt()) + assertEquals(testSettingsPackageName, + TetheringNotificationUpdater.getSettingsPackageName(pm)) + } } diff --git a/services/core/java/com/android/server/AppStateTracker.java b/services/core/java/com/android/server/AppStateTracker.java index b765d81d42b7..74f79e0d40f5 100644 --- a/services/core/java/com/android/server/AppStateTracker.java +++ b/services/core/java/com/android/server/AppStateTracker.java @@ -1120,7 +1120,8 @@ public class AppStateTracker { return false; } final int userId = UserHandle.getUserId(uid); - if (mExemptedPackages.contains(userId, packageName)) { + if (mAppStandbyInternal.isAppIdleEnabled() && !mAppStandbyInternal.isInParole() + && mExemptedPackages.contains(userId, packageName)) { return false; } return mForceAllAppsStandby; diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java index 067bdcb111fb..bfcbe465a271 100644 --- a/services/core/java/com/android/server/location/LocationManagerService.java +++ b/services/core/java/com/android/server/location/LocationManagerService.java @@ -231,7 +231,7 @@ public class LocationManagerService extends ILocationManager.Stub { private final AppForegroundHelper mAppForegroundHelper; private final LocationUsageLogger mLocationUsageLogger; - @Nullable private GnssManagerService mGnssManagerService = null; + @Nullable private volatile GnssManagerService mGnssManagerService = null; private final PassiveLocationProviderManager mPassiveManager; @@ -381,6 +381,10 @@ public class LocationManagerService extends ILocationManager.Stub { // prepare providers initializeProvidersLocked(); } + + // initialize gnss last because it has no awareness of boot phases and blindly assumes that + // all other location providers are loaded at initialization + initializeGnss(); } private void onAppOpChanged(String packageName) { @@ -602,16 +606,19 @@ public class LocationManagerService extends ILocationManager.Stub { } manager.setMockProvider(new MockProvider(properties)); } + } - // initialize gnss last because it has no awareness of boot phases and blindly assumes that - // all other location providers are loaded at initialization + private void initializeGnss() { + // Do not hold mLock when calling GnssManagerService#isGnssSupported() which calls into HAL. if (GnssManagerService.isGnssSupported()) { mGnssManagerService = new GnssManagerService(mContext, mAppOpsHelper, mSettingsHelper, mAppForegroundHelper, mLocationUsageLogger); mGnssManagerService.onSystemReady(); LocationProviderManager gnssManager = new LocationProviderManager(GPS_PROVIDER); - mProviderManagers.add(gnssManager); + synchronized (mLock) { + mProviderManagers.add(gnssManager); + } gnssManager.setRealProvider(mGnssManagerService.getGnssLocationProvider()); // bind to geofence proxy diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java index ba60f179e661..4b6ee71803a7 100644 --- a/services/core/java/com/android/server/pm/AppsFilter.java +++ b/services/core/java/com/android/server/pm/AppsFilter.java @@ -19,8 +19,6 @@ package com.android.server.pm; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE; -import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; - import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; @@ -111,25 +109,12 @@ public class AppsFilter { private final boolean mSystemAppsQueryable; private final FeatureConfig mFeatureConfig; - private final OverlayReferenceMapper mOverlayReferenceMapper; - private final StateProvider mStateProvider; + private final OverlayReferenceMapper mOverlayReferenceMapper; private PackageParser.SigningDetails mSystemSigningDetails; private Set<String> mProtectedBroadcasts = new ArraySet<>(); - /** - * This structure maps uid -> uid and indicates whether access from the first should be - * filtered to the second. It's essentially a cache of the - * {@link #shouldFilterApplicationInternal(int, SettingBase, PackageSetting, int)} call. - * NOTE: It can only be relied upon after the system is ready to avoid unnecessary update on - * initial scan and is null until {@link #onSystemReady()} is called. - */ - private volatile SparseArray<SparseBooleanArray> mShouldFilterCache; - - @VisibleForTesting(visibility = PRIVATE) - AppsFilter(StateProvider stateProvider, - FeatureConfig featureConfig, - String[] forceQueryableWhitelist, + AppsFilter(FeatureConfig featureConfig, String[] forceQueryableWhitelist, boolean systemAppsQueryable, @Nullable OverlayReferenceMapper.Provider overlayProvider) { mFeatureConfig = featureConfig; @@ -137,23 +122,8 @@ public class AppsFilter { mSystemAppsQueryable = systemAppsQueryable; mOverlayReferenceMapper = new OverlayReferenceMapper(true /*deferRebuild*/, overlayProvider); - mStateProvider = stateProvider; - } - - /** - * Provides system state to AppsFilter via {@link CurrentStateCallback} after properly guarding - * the data with the package lock. - */ - @VisibleForTesting(visibility = PRIVATE) - public interface StateProvider { - void runWithState(CurrentStateCallback callback); - - interface CurrentStateCallback { - void currentState(ArrayMap<String, PackageSetting> settings, int[] users); - } } - @VisibleForTesting(visibility = PRIVATE) public interface FeatureConfig { /** Called when the system is ready and components can be queried. */ @@ -170,7 +140,6 @@ public class AppsFilter { /** * Turns on logging for the given appId - * * @param enable true if logging should be enabled, false if disabled. */ void enableLogging(int appId, boolean enable); @@ -178,7 +147,6 @@ public class AppsFilter { /** * Initializes the package enablement state for the given package. This gives opportunity * to do any expensive operations ahead of the actual checks. - * * @param removed true if adding, false if removing */ void updatePackageState(PackageSetting setting, boolean removed); @@ -194,7 +162,6 @@ public class AppsFilter { @Nullable private SparseBooleanArray mLoggingEnabled = null; - private AppsFilter mAppsFilter; private FeatureConfigImpl( PackageManagerInternal pmInternal, PackageManagerService.Injector injector) { @@ -202,10 +169,6 @@ public class AppsFilter { mInjector = injector; } - public void setAppsFilter(AppsFilter filter) { - mAppsFilter = filter; - } - @Override public void onSystemReady() { mFeatureEnabled = DeviceConfig.getBoolean( @@ -272,28 +235,27 @@ public class AppsFilter { @Override public void onCompatChange(String packageName) { + updateEnabledState(mPmInternal.getPackage(packageName)); + } + + private void updateEnabledState(AndroidPackage pkg) { final long token = Binder.clearCallingIdentity(); try { - updateEnabledState(mPmInternal.getPackage(packageName)); - mAppsFilter.updateShouldFilterCacheForPackage(packageName); + // TODO(b/135203078): Do not use toAppInfo + final boolean enabled = + mInjector.getCompatibility().isChangeEnabled( + PackageManager.FILTER_APPLICATION_QUERY, + pkg.toAppInfoWithoutState()); + if (enabled) { + mDisabledPackages.remove(pkg.getPackageName()); + } else { + mDisabledPackages.add(pkg.getPackageName()); + } } finally { Binder.restoreCallingIdentity(token); } } - private void updateEnabledState(AndroidPackage pkg) { - // TODO(b/135203078): Do not use toAppInfo - final boolean enabled = - mInjector.getCompatibility().isChangeEnabled( - PackageManager.FILTER_APPLICATION_QUERY, - pkg.toAppInfoWithoutState()); - if (enabled) { - mDisabledPackages.remove(pkg.getPackageName()); - } else { - mDisabledPackages.add(pkg.getPackageName()); - } - } - @Override public void updatePackageState(PackageSetting setting, boolean removed) { final boolean enableLogging = @@ -313,7 +275,7 @@ public class AppsFilter { final boolean forceSystemAppsQueryable = injector.getContext().getResources() .getBoolean(R.bool.config_forceSystemPackagesQueryable); - final FeatureConfigImpl featureConfig = new FeatureConfigImpl(pms, injector); + final FeatureConfig featureConfig = new FeatureConfigImpl(pms, injector); final String[] forcedQueryablePackageNames; if (forceSystemAppsQueryable) { // all system apps already queryable, no need to read and parse individual exceptions @@ -326,16 +288,8 @@ public class AppsFilter { forcedQueryablePackageNames[i] = forcedQueryablePackageNames[i].intern(); } } - final StateProvider stateProvider = command -> { - synchronized (injector.getLock()) { - command.currentState(injector.getSettings().mPackages, - injector.getUserManagerInternal().getUserIds()); - } - }; - AppsFilter appsFilter = new AppsFilter(stateProvider, featureConfig, - forcedQueryablePackageNames, forceSystemAppsQueryable, null); - featureConfig.setAppsFilter(appsFilter); - return appsFilter; + return new AppsFilter(featureConfig, forcedQueryablePackageNames, + forceSystemAppsQueryable, null); } public FeatureConfig getFeatureConfig() { @@ -458,54 +412,28 @@ public class AppsFilter { * visibility of the caller from the target. * * @param recipientUid the uid gaining visibility of the {@code visibleUid}. - * @param visibleUid the uid becoming visible to the {@recipientUid} + * @param visibleUid the uid becoming visible to the {@recipientUid} */ public void grantImplicitAccess(int recipientUid, int visibleUid) { - if (recipientUid != visibleUid) { - if (mImplicitlyQueryable.add(recipientUid, visibleUid) && DEBUG_LOGGING) { - Slog.i(TAG, "implicit access granted: " + recipientUid + " -> " + visibleUid); - } - if (mShouldFilterCache != null) { - // update the cache in a one-off manner since we've got all the information we need. - SparseBooleanArray visibleUids = mShouldFilterCache.get(recipientUid); - if (visibleUids == null) { - visibleUids = new SparseBooleanArray(); - mShouldFilterCache.put(recipientUid, visibleUids); - } - visibleUids.put(visibleUid, false); - } + if (recipientUid != visibleUid + && mImplicitlyQueryable.add(recipientUid, visibleUid) && DEBUG_LOGGING) { + Slog.i(TAG, "implicit access granted: " + recipientUid + " -> " + visibleUid); } } public void onSystemReady() { - mShouldFilterCache = new SparseArray<>(); mFeatureConfig.onSystemReady(); mOverlayReferenceMapper.rebuildIfDeferred(); - updateEntireShouldFilterCache(); } /** * Adds a package that should be considered when filtering visibility between apps. * - * @param newPkgSetting the new setting being added + * @param newPkgSetting the new setting being added + * @param existingSettings all other settings currently on the device. */ - public void addPackage(PackageSetting newPkgSetting) { - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "filter.addPackage"); - try { - mStateProvider.runWithState((settings, users) -> { - addPackageInternal(newPkgSetting, settings, users); - if (mShouldFilterCache != null) { - updateShouldFilterCacheForPackage( - null, newPkgSetting, settings, users, settings.size()); - } // else, rebuild entire cache when system is ready - }); - } finally { - Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); - } - } - - private void addPackageInternal(PackageSetting newPkgSetting, - ArrayMap<String, PackageSetting> existingSettings, int[] allUsers) { + public void addPackage(PackageSetting newPkgSetting, + ArrayMap<String, PackageSetting> existingSettings) { if (Objects.equals("android", newPkgSetting.name)) { // let's set aside the framework signatures mSystemSigningDetails = newPkgSetting.signatures.mSigningDetails; @@ -518,151 +446,79 @@ public class AppsFilter { } } - final AndroidPackage newPkg = newPkgSetting.pkg; - if (newPkg == null) { - // nothing to add - return; - } - - if (!newPkg.getProtectedBroadcasts().isEmpty()) { - mProtectedBroadcasts.addAll(newPkg.getProtectedBroadcasts()); - recomputeComponentVisibility(existingSettings, newPkg.getPackageName()); - } + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "filter.addPackage"); + try { + final AndroidPackage newPkg = newPkgSetting.pkg; + if (newPkg == null) { + // nothing to add + return; + } - final boolean newIsForceQueryable = - mForceQueryable.contains(newPkgSetting.appId) - /* shared user that is already force queryable */ - || newPkg.isForceQueryable() - || newPkgSetting.forceQueryableOverride - || (newPkgSetting.isSystem() && (mSystemAppsQueryable - || ArrayUtils.contains(mForceQueryableByDevicePackageNames, - newPkg.getPackageName()))); - if (newIsForceQueryable - || (mSystemSigningDetails != null - && isSystemSigned(mSystemSigningDetails, newPkgSetting))) { - mForceQueryable.add(newPkgSetting.appId); - } + if (!newPkg.getProtectedBroadcasts().isEmpty()) { + mProtectedBroadcasts.addAll(newPkg.getProtectedBroadcasts()); + recomputeComponentVisibility(existingSettings, newPkg.getPackageName()); + } - for (int i = existingSettings.size() - 1; i >= 0; i--) { - final PackageSetting existingSetting = existingSettings.valueAt(i); - if (existingSetting.appId == newPkgSetting.appId || existingSetting.pkg == null) { - continue; + final boolean newIsForceQueryable = + mForceQueryable.contains(newPkgSetting.appId) + /* shared user that is already force queryable */ + || newPkg.isForceQueryable() + || newPkgSetting.forceQueryableOverride + || (newPkgSetting.isSystem() && (mSystemAppsQueryable + || ArrayUtils.contains(mForceQueryableByDevicePackageNames, + newPkg.getPackageName()))); + if (newIsForceQueryable + || (mSystemSigningDetails != null + && isSystemSigned(mSystemSigningDetails, newPkgSetting))) { + mForceQueryable.add(newPkgSetting.appId); } - final AndroidPackage existingPkg = existingSetting.pkg; - // let's evaluate the ability of already added packages to see this new package - if (!newIsForceQueryable) { - if (canQueryViaComponents(existingPkg, newPkg, mProtectedBroadcasts)) { - mQueriesViaComponent.add(existingSetting.appId, newPkgSetting.appId); + + for (int i = existingSettings.size() - 1; i >= 0; i--) { + final PackageSetting existingSetting = existingSettings.valueAt(i); + if (existingSetting.appId == newPkgSetting.appId || existingSetting.pkg == null) { + continue; } - if (canQueryViaPackage(existingPkg, newPkg) - || canQueryAsInstaller(existingSetting, newPkg)) { - mQueriesViaPackage.add(existingSetting.appId, newPkgSetting.appId); + final AndroidPackage existingPkg = existingSetting.pkg; + // let's evaluate the ability of already added packages to see this new package + if (!newIsForceQueryable) { + if (canQueryViaComponents(existingPkg, newPkg, mProtectedBroadcasts)) { + mQueriesViaComponent.add(existingSetting.appId, newPkgSetting.appId); + } + if (canQueryViaPackage(existingPkg, newPkg) + || canQueryAsInstaller(existingSetting, newPkg)) { + mQueriesViaPackage.add(existingSetting.appId, newPkgSetting.appId); + } } - } - // now we'll evaluate our new package's ability to see existing packages - if (!mForceQueryable.contains(existingSetting.appId)) { - if (canQueryViaComponents(newPkg, existingPkg, mProtectedBroadcasts)) { - mQueriesViaComponent.add(newPkgSetting.appId, existingSetting.appId); + // now we'll evaluate our new package's ability to see existing packages + if (!mForceQueryable.contains(existingSetting.appId)) { + if (canQueryViaComponents(newPkg, existingPkg, mProtectedBroadcasts)) { + mQueriesViaComponent.add(newPkgSetting.appId, existingSetting.appId); + } + if (canQueryViaPackage(newPkg, existingPkg) + || canQueryAsInstaller(newPkgSetting, existingPkg)) { + mQueriesViaPackage.add(newPkgSetting.appId, existingSetting.appId); + } } - if (canQueryViaPackage(newPkg, existingPkg) - || canQueryAsInstaller(newPkgSetting, existingPkg)) { + // if either package instruments the other, mark both as visible to one another + if (pkgInstruments(newPkgSetting, existingSetting) + || pkgInstruments(existingSetting, newPkgSetting)) { mQueriesViaPackage.add(newPkgSetting.appId, existingSetting.appId); + mQueriesViaPackage.add(existingSetting.appId, newPkgSetting.appId); } } - // if either package instruments the other, mark both as visible to one another - if (pkgInstruments(newPkgSetting, existingSetting) - || pkgInstruments(existingSetting, newPkgSetting)) { - mQueriesViaPackage.add(newPkgSetting.appId, existingSetting.appId); - mQueriesViaPackage.add(existingSetting.appId, newPkgSetting.appId); - } - } - - int existingSize = existingSettings.size(); - ArrayMap<String, AndroidPackage> existingPkgs = new ArrayMap<>(existingSize); - for (int index = 0; index < existingSize; index++) { - PackageSetting pkgSetting = existingSettings.valueAt(index); - if (pkgSetting.pkg != null) { - existingPkgs.put(pkgSetting.name, pkgSetting.pkg); - } - } - mOverlayReferenceMapper.addPkg(newPkgSetting.pkg, existingPkgs); - mFeatureConfig.updatePackageState(newPkgSetting, false /*removed*/); - } - - private void removeAppIdFromVisibilityCache(int appId) { - if (mShouldFilterCache == null) { - return; - } - for (int i = mShouldFilterCache.size() - 1; i >= 0; i--) { - if (UserHandle.getAppId(mShouldFilterCache.keyAt(i)) == appId) { - mShouldFilterCache.removeAt(i); - continue; - } - SparseBooleanArray targetSparseArray = mShouldFilterCache.valueAt(i); - for (int j = targetSparseArray.size() - 1; j >= 0; j--) { - if (UserHandle.getAppId(targetSparseArray.keyAt(j)) == appId) { - targetSparseArray.removeAt(j); - } - } - } - } - - private void updateEntireShouldFilterCache() { - mStateProvider.runWithState((settings, users) -> { - mShouldFilterCache.clear(); - for (int i = settings.size() - 1; i >= 0; i--) { - updateShouldFilterCacheForPackage( - null /*skipPackage*/, settings.valueAt(i), settings, users, i); - } - }); - } - - public void onUsersChanged() { - if (mShouldFilterCache != null) { - updateEntireShouldFilterCache(); - } - } - private void updateShouldFilterCacheForPackage(String packageName) { - mStateProvider.runWithState((settings, users) -> { - updateShouldFilterCacheForPackage(null /* skipPackage */, settings.get(packageName), - settings, users, settings.size() /*maxIndex*/); - }); - - } - - private void updateShouldFilterCacheForPackage(@Nullable String skipPackageName, - PackageSetting subjectSetting, ArrayMap<String, PackageSetting> allSettings, - int[] allUsers, int maxIndex) { - for (int i = Math.min(maxIndex, allSettings.size() - 1); i >= 0; i--) { - PackageSetting otherSetting = allSettings.valueAt(i); - if (subjectSetting.appId == otherSetting.appId) { - continue; - } - //noinspection StringEquality - if (subjectSetting.name == skipPackageName || otherSetting.name == skipPackageName) { - continue; - } - for (int su = 0; su < allUsers.length; su++) { - int subjectUser = allUsers[su]; - for (int ou = su; ou < allUsers.length; ou++) { - int otherUser = allUsers[ou]; - int subjectUid = UserHandle.getUid(subjectUser, subjectSetting.appId); - if (!mShouldFilterCache.contains(subjectUid)) { - mShouldFilterCache.put(subjectUid, new SparseBooleanArray()); - } - int otherUid = UserHandle.getUid(otherUser, otherSetting.appId); - if (!mShouldFilterCache.contains(otherUid)) { - mShouldFilterCache.put(otherUid, new SparseBooleanArray()); - } - mShouldFilterCache.get(subjectUid).put(otherUid, - shouldFilterApplicationInternal( - subjectUid, subjectSetting, otherSetting, otherUser)); - mShouldFilterCache.get(otherUid).put(subjectUid, - shouldFilterApplicationInternal( - otherUid, otherSetting, subjectSetting, subjectUser)); + int existingSize = existingSettings.size(); + ArrayMap<String, AndroidPackage> existingPkgs = new ArrayMap<>(existingSize); + for (int index = 0; index < existingSize; index++) { + PackageSetting pkgSetting = existingSettings.valueAt(index); + if (pkgSetting.pkg != null) { + existingPkgs.put(pkgSetting.name, pkgSetting.pkg); } } + mOverlayReferenceMapper.addPkg(newPkgSetting.pkg, existingPkgs); + mFeatureConfig.updatePackageState(newPkgSetting, false /*removed*/); + } finally { + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } @@ -713,7 +569,6 @@ public class AppsFilter { } } } - /** * Fetches all app Ids that a given setting is currently visible to, per provided user. This * only includes UIDs >= {@link Process#FIRST_APPLICATION_UID} as all other UIDs can already see @@ -722,11 +577,11 @@ public class AppsFilter { * If the setting is visible to all UIDs, null is returned. If an app is not visible to any * applications, the int array will be empty. * - * @param users the set of users that should be evaluated for this calculation + * @param users the set of users that should be evaluated for this calculation * @param existingSettings the set of all package settings that currently exist on device * @return a SparseArray mapping userIds to a sorted int array of appIds that may view the - * provided setting or null if the app is visible to all and no whitelist should be - * applied. + * provided setting or null if the app is visible to all and no whitelist should be + * applied. */ @Nullable public SparseArray<int[]> getVisibilityWhitelist(PackageSetting setting, int[] users, @@ -771,60 +626,52 @@ public class AppsFilter { /** * Removes a package for consideration when filtering visibility between apps. * - * @param setting the setting of the package being removed. + * @param setting the setting of the package being removed. + * @param allUsers array of all current users on device. */ - public void removePackage(PackageSetting setting) { - removeAppIdFromVisibilityCache(setting.appId); - mStateProvider.runWithState((settings, users) -> { - for (int u = 0; u < users.length; u++) { - final int userId = users[u]; - final int removingUid = UserHandle.getUid(userId, setting.appId); - mImplicitlyQueryable.remove(removingUid); - for (int i = mImplicitlyQueryable.size() - 1; i >= 0; i--) { - mImplicitlyQueryable.remove(mImplicitlyQueryable.keyAt(i), removingUid); - } - } - - mQueriesViaComponent.remove(setting.appId); - for (int i = mQueriesViaComponent.size() - 1; i >= 0; i--) { - mQueriesViaComponent.remove(mQueriesViaComponent.keyAt(i), setting.appId); - } - mQueriesViaPackage.remove(setting.appId); - for (int i = mQueriesViaPackage.size() - 1; i >= 0; i--) { - mQueriesViaPackage.remove(mQueriesViaPackage.keyAt(i), setting.appId); - } - - // re-add other shared user members to re-establish visibility between them and other - // packages - if (setting.sharedUser != null) { - for (int i = setting.sharedUser.packages.size() - 1; i >= 0; i--) { - if (setting.sharedUser.packages.valueAt(i) == setting) { - continue; - } - addPackageInternal( - setting.sharedUser.packages.valueAt(i), settings, users); - } - } + public void removePackage(PackageSetting setting, int[] allUsers, + ArrayMap<String, PackageSetting> existingSettings) { + mForceQueryable.remove(setting.appId); - if (!setting.pkg.getProtectedBroadcasts().isEmpty()) { - final String removingPackageName = setting.pkg.getPackageName(); - mProtectedBroadcasts.clear(); - mProtectedBroadcasts.addAll( - collectProtectedBroadcasts(settings, removingPackageName)); - recomputeComponentVisibility(settings, removingPackageName); + for (int u = 0; u < allUsers.length; u++) { + final int userId = allUsers[u]; + final int removingUid = UserHandle.getUid(userId, setting.appId); + mImplicitlyQueryable.remove(removingUid); + for (int i = mImplicitlyQueryable.size() - 1; i >= 0; i--) { + mImplicitlyQueryable.remove(mImplicitlyQueryable.keyAt(i), removingUid); } + } - mOverlayReferenceMapper.removePkg(setting.name); - mFeatureConfig.updatePackageState(setting, true /*removed*/); + mQueriesViaComponent.remove(setting.appId); + for (int i = mQueriesViaComponent.size() - 1; i >= 0; i--) { + mQueriesViaComponent.remove(mQueriesViaComponent.keyAt(i), setting.appId); + } + mQueriesViaPackage.remove(setting.appId); + for (int i = mQueriesViaPackage.size() - 1; i >= 0; i--) { + mQueriesViaPackage.remove(mQueriesViaPackage.keyAt(i), setting.appId); + } - if (mShouldFilterCache != null) { - updateShouldFilterCacheForPackage( - setting.name, setting, settings, users, settings.size()); + // re-add other shared user members to re-establish visibility between them and other + // packages + if (setting.sharedUser != null) { + for (int i = setting.sharedUser.packages.size() - 1; i >= 0; i--) { + if (setting.sharedUser.packages.valueAt(i) == setting) { + continue; + } + addPackage(setting.sharedUser.packages.valueAt(i), existingSettings); } - }); - mForceQueryable.remove(setting.appId); + } + if (!setting.pkg.getProtectedBroadcasts().isEmpty()) { + final String removingPackageName = setting.pkg.getPackageName(); + mProtectedBroadcasts.clear(); + mProtectedBroadcasts.addAll( + collectProtectedBroadcasts(existingSettings, removingPackageName)); + recomputeComponentVisibility(existingSettings, removingPackageName); + } + mOverlayReferenceMapper.removePkg(setting.name); + mFeatureConfig.updatePackageState(setting, true /*removed*/); } /** @@ -841,32 +688,11 @@ public class AppsFilter { PackageSetting targetPkgSetting, int userId) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "shouldFilterApplication"); try { - if (callingUid < Process.FIRST_APPLICATION_UID - || UserHandle.getAppId(callingUid) == targetPkgSetting.appId) { + + if (!shouldFilterApplicationInternal( + callingUid, callingSetting, targetPkgSetting, userId)) { return false; } - if (mShouldFilterCache != null) { // use cache - SparseBooleanArray shouldFilterTargets = mShouldFilterCache.get(callingUid); - final int targetUid = UserHandle.getUid(userId, targetPkgSetting.appId); - if (shouldFilterTargets == null) { - Slog.wtf(TAG, "Encountered calling uid with no cached rules: " + callingUid); - return true; - } - int indexOfTargetUid = shouldFilterTargets.indexOfKey(targetUid); - if (indexOfTargetUid < 0) { - Slog.w(TAG, "Encountered calling -> target with no cached rules: " - + callingUid + " -> " + targetUid); - return true; - } - if (!shouldFilterTargets.valueAt(indexOfTargetUid)) { - return false; - } - } else { - if (!shouldFilterApplicationInternal( - callingUid, callingSetting, targetPkgSetting, userId)) { - return false; - } - } if (DEBUG_LOGGING || mFeatureConfig.isLoggingEnabled(UserHandle.getAppId(callingUid))) { log(callingSetting, targetPkgSetting, "BLOCKED"); } @@ -877,7 +703,7 @@ public class AppsFilter { } private boolean shouldFilterApplicationInternal(int callingUid, SettingBase callingSetting, - PackageSetting targetPkgSetting, int targetUserId) { + PackageSetting targetPkgSetting, int userId) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "shouldFilterApplicationInternal"); try { final boolean featureEnabled = mFeatureConfig.isGloballyEnabled(); @@ -887,6 +713,12 @@ public class AppsFilter { } return false; } + if (callingUid < Process.FIRST_APPLICATION_UID) { + if (DEBUG_LOGGING) { + Slog.d(TAG, "filtering skipped; " + callingUid + " is system"); + } + return false; + } if (callingSetting == null) { Slog.wtf(TAG, "No setting found for non system uid " + callingUid); return true; @@ -895,14 +727,8 @@ public class AppsFilter { final ArraySet<PackageSetting> callingSharedPkgSettings; Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "callingSetting instanceof"); if (callingSetting instanceof PackageSetting) { - if (((PackageSetting) callingSetting).sharedUser == null) { - callingPkgSetting = (PackageSetting) callingSetting; - callingSharedPkgSettings = null; - } else { - callingPkgSetting = null; - callingSharedPkgSettings = - ((PackageSetting) callingSetting).sharedUser.packages; - } + callingPkgSetting = (PackageSetting) callingSetting; + callingSharedPkgSettings = null; } else { callingPkgSetting = null; callingSharedPkgSettings = ((SharedUserSetting) callingSetting).packages; @@ -960,17 +786,13 @@ public class AppsFilter { } try { - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "requestsQueryAllPackages"); - if (callingPkgSetting != null) { - if (requestsQueryAllPackages(callingPkgSetting)) { - return false; - } - } else { - for (int i = callingSharedPkgSettings.size() - 1; i >= 0; i--) { - if (requestsQueryAllPackages(callingSharedPkgSettings.valueAt(i))) { - return false; - } + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "hasPermission"); + if (callingSetting.getPermissionsState().hasPermission( + Manifest.permission.QUERY_ALL_PACKAGES, UserHandle.getUserId(callingUid))) { + if (DEBUG_LOGGING) { + log(callingSetting, targetPkgSetting, "has query-all permission"); } + return false; } } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); @@ -1011,7 +833,7 @@ public class AppsFilter { try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mImplicitlyQueryable"); - final int targetUid = UserHandle.getUid(targetUserId, targetAppId); + final int targetUid = UserHandle.getUid(userId, targetAppId); if (mImplicitlyQueryable.contains(callingUid, targetUid)) { if (DEBUG_LOGGING) { log(callingSetting, targetPkgSetting, "implicitly queryable for user"); @@ -1049,20 +871,13 @@ public class AppsFilter { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } + return true; } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } - - private static boolean requestsQueryAllPackages(PackageSetting pkgSetting) { - // we're not guaranteed to have permissions yet analyzed at package add, so we inspect the - // package directly - return pkgSetting.pkg.getRequestedPermissions().contains( - Manifest.permission.QUERY_ALL_PACKAGES); - } - /** Returns {@code true} if the source package instruments the target package. */ private static boolean pkgInstruments(PackageSetting source, PackageSetting target) { try { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index fd37f041450e..5e5274849fcd 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -12362,7 +12362,7 @@ public class PackageManagerService extends IPackageManager.Stub ksms.addScannedPackageLPw(pkg); mComponentResolver.addAllComponents(pkg, chatty); - mAppsFilter.addPackage(pkgSetting); + mAppsFilter.addPackage(pkgSetting, mSettings.mPackages); // Don't allow ephemeral applications to define new permissions groups. if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) { @@ -12536,6 +12536,8 @@ public class PackageManagerService extends IPackageManager.Stub void cleanPackageDataStructuresLILPw(AndroidPackage pkg, boolean chatty) { mComponentResolver.removeAllComponents(pkg, chatty); + mAppsFilter.removePackage(getPackageSetting(pkg.getPackageName()), + mInjector.getUserManagerInternal().getUserIds(), mSettings.mPackages); mPermissionManager.removeAllPermissions(pkg, chatty); final int instrumentationSize = ArrayUtils.size(pkg.getInstrumentations()); @@ -14251,7 +14253,7 @@ public class PackageManagerService extends IPackageManager.Stub // Okay! targetPackageSetting.setInstallerPackageName(installerPackageName); mSettings.addInstallerPackageNames(targetPackageSetting.installSource); - mAppsFilter.addPackage(targetPackageSetting); + mAppsFilter.addPackage(targetPackageSetting, mSettings.mPackages); scheduleWriteSettingsLocked(); } } @@ -18704,7 +18706,6 @@ public class PackageManagerService extends IPackageManager.Stub clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL, true); clearDefaultBrowserIfNeeded(packageName); mSettings.mKeySetManagerService.removeAppKeySetDataLPw(packageName); - mAppsFilter.removePackage(getPackageSetting(packageName)); removedAppId = mSettings.removePackageLPw(packageName); if (outInfo != null) { outInfo.removedAppId = removedAppId; @@ -23462,7 +23463,6 @@ public class PackageManagerService extends IPackageManager.Stub scheduleWritePackageRestrictionsLocked(userId); scheduleWritePackageListLocked(userId); primeDomainVerificationsLPw(userId); - mAppsFilter.onUsersChanged(); } } diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java index 2f963b7e6b35..522e5e189232 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java @@ -20,8 +20,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback; import android.hardware.soundtrigger.V2_2.ISoundTriggerHw; -import android.media.audio.common.AudioConfig; -import android.media.audio.common.AudioOffloadInfo; import android.media.soundtrigger_middleware.ISoundTriggerCallback; import android.media.soundtrigger_middleware.ISoundTriggerModule; import android.media.soundtrigger_middleware.ModelParameterRange; @@ -30,6 +28,7 @@ import android.media.soundtrigger_middleware.PhraseRecognitionExtra; import android.media.soundtrigger_middleware.PhraseSoundModel; import android.media.soundtrigger_middleware.RecognitionConfig; import android.media.soundtrigger_middleware.RecognitionEvent; +import android.media.soundtrigger_middleware.RecognitionStatus; import android.media.soundtrigger_middleware.SoundModel; import android.media.soundtrigger_middleware.SoundModelType; import android.media.soundtrigger_middleware.SoundTriggerModuleProperties; @@ -579,7 +578,7 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { @NonNull ISoundTriggerHwCallback.RecognitionEvent recognitionEvent, int cookie) { synchronized (SoundTriggerModule.this) { - android.media.soundtrigger_middleware.RecognitionEvent aidlEvent = + RecognitionEvent aidlEvent = ConversionUtil.hidl2aidlRecognitionEvent(recognitionEvent); aidlEvent.captureSession = mSession.mSessionHandle; try { @@ -589,8 +588,7 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { // In any case, client callbacks are considered best effort. Log.e(TAG, "Client callback execption.", e); } - if (aidlEvent.status - != android.media.soundtrigger_middleware.RecognitionStatus.FORCED) { + if (aidlEvent.status != RecognitionStatus.FORCED) { setState(ModelState.LOADED); } } @@ -601,7 +599,7 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { @NonNull ISoundTriggerHwCallback.PhraseRecognitionEvent phraseRecognitionEvent, int cookie) { synchronized (SoundTriggerModule.this) { - android.media.soundtrigger_middleware.PhraseRecognitionEvent aidlEvent = + PhraseRecognitionEvent aidlEvent = ConversionUtil.hidl2aidlPhraseRecognitionEvent(phraseRecognitionEvent); aidlEvent.common.captureSession = mSession.mSessionHandle; try { @@ -611,8 +609,7 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { // In any case, client callbacks are considered best effort. Log.e(TAG, "Client callback execption.", e); } - if (aidlEvent.common.status - != android.media.soundtrigger_middleware.RecognitionStatus.FORCED) { + if (aidlEvent.common.status != RecognitionStatus.FORCED) { setState(ModelState.LOADED); } } @@ -623,15 +620,13 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { /** * Creates a default-initialized recognition event. * - * Object fields are default constructed. - * Array fields are initialized to 0 length. + * Non-nullable object fields are default constructed. + * Non-nullable array fields are initialized to 0 length. * * @return The event. */ private static RecognitionEvent newEmptyRecognitionEvent() { RecognitionEvent result = new RecognitionEvent(); - result.audioConfig = new AudioConfig(); - result.audioConfig.offloadInfo = new AudioOffloadInfo(); result.data = new byte[0]; return result; } @@ -639,8 +634,8 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient { /** * Creates a default-initialized phrase recognition event. * - * Object fields are default constructed. - * Array fields are initialized to 0 length. + * Non-nullable object fields are default constructed. + * Non-nullable array fields are initialized to 0 length. * * @return The event. */ diff --git a/services/core/java/com/android/server/textclassifier/FixedSizeQueue.java b/services/core/java/com/android/server/textclassifier/FixedSizeQueue.java new file mode 100644 index 000000000000..edb258db88c8 --- /dev/null +++ b/services/core/java/com/android/server/textclassifier/FixedSizeQueue.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.textclassifier; + +import android.annotation.NonNull; +import android.annotation.Nullable; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.Preconditions; + +import java.util.ArrayDeque; +import java.util.Objects; +import java.util.Queue; + +/** + * A fixed-size queue which automatically evicts the oldest element from the queue when it is full. + * + * <p>This class does not accept null element. + * + * @param <E> the type of elements held in this queue + */ +@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) +public final class FixedSizeQueue<E> { + + private final Queue<E> mDelegate; + + @Nullable + private final OnEntryEvictedListener<E> mOnEntryEvictedListener; + + private final int mMaxSize; + + public FixedSizeQueue(int maxSize, @Nullable OnEntryEvictedListener<E> onEntryEvictedListener) { + Preconditions.checkArgument(maxSize > 0, "maxSize (%s) must > 0", maxSize); + mDelegate = new ArrayDeque<>(maxSize); + mMaxSize = maxSize; + mOnEntryEvictedListener = onEntryEvictedListener; + } + + /** Returns the number of items in the queue. */ + public int size() { + return mDelegate.size(); + } + + /** Adds an element to the queue, evicts the oldest element if it reaches its max capacity. */ + public boolean add(@NonNull E element) { + Objects.requireNonNull(element); + if (size() == mMaxSize) { + E removed = mDelegate.remove(); + if (mOnEntryEvictedListener != null) { + mOnEntryEvictedListener.onEntryEvicted(removed); + } + } + mDelegate.add(element); + return true; + } + + /** + * Returns and removes the head of the queue, or returns null if this queue is empty. + */ + @Nullable + public E poll() { + return mDelegate.poll(); + } + + /** + * Removes an element from the queue, returns a boolean to indicate if an element is removed. + */ + public boolean remove(@NonNull E element) { + Objects.requireNonNull(element); + return mDelegate.remove(element); + } + + /** Returns whether the queue is empty. */ + public boolean isEmpty() { + return mDelegate.isEmpty(); + } + + /** + * A listener to get notified when an element is evicted. + * + * @param <E> the type of element + */ + public interface OnEntryEvictedListener<E> { + /** + * Notifies that an element is evicted because the queue is reaching its max capacity. + */ + void onEntryEvicted(@NonNull E element); + } +} diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java index 1c96a2e8c5c2..1707d9542813 100644 --- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java +++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java @@ -41,6 +41,7 @@ import android.service.textclassifier.TextClassifierService; import android.service.textclassifier.TextClassifierService.ConnectionState; import android.text.TextUtils; import android.util.ArrayMap; +import android.util.LruCache; import android.util.Slog; import android.util.SparseArray; import android.view.textclassifier.ConversationAction; @@ -68,12 +69,10 @@ import com.android.server.SystemService; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.util.ArrayDeque; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Queue; /** * A manager for TextClassifier services. @@ -308,13 +307,15 @@ public final class TextClassificationManagerService extends ITextClassifierServi Objects.requireNonNull(classificationContext); Objects.requireNonNull(classificationContext.getSystemTextClassifierMetadata()); + synchronized (mLock) { + mSessionCache.put(sessionId, classificationContext); + } handleRequest( classificationContext.getSystemTextClassifierMetadata(), /* verifyCallingPackage= */ true, /* attemptToBind= */ false, service -> { service.onCreateTextClassificationSession(classificationContext, sessionId); - mSessionCache.put(sessionId, classificationContext); }, "onCreateTextClassificationSession", NO_OP_CALLBACK); @@ -588,12 +589,14 @@ public final class TextClassificationManagerService extends ITextClassifierServi * are cleaned up automatically when the client process is dead. */ static final class SessionCache { + private static final int MAX_CACHE_SIZE = 100; + @NonNull private final Object mLock; @NonNull @GuardedBy("mLock") - private final Map<TextClassificationSessionId, StrippedTextClassificationContext> mCache = - new ArrayMap<>(); + private final LruCache<TextClassificationSessionId, StrippedTextClassificationContext> + mCache = new LruCache<>(MAX_CACHE_SIZE); @NonNull @GuardedBy("mLock") private final Map<TextClassificationSessionId, DeathRecipient> mDeathRecipients = @@ -775,6 +778,8 @@ public final class TextClassificationManagerService extends ITextClassifierServi } private final class ServiceState { + private static final int MAX_PENDING_REQUESTS = 20; + @UserIdInt final int mUserId; @NonNull @@ -786,7 +791,15 @@ public final class TextClassificationManagerService extends ITextClassifierServi final int mBindServiceFlags; @NonNull @GuardedBy("mLock") - final Queue<PendingRequest> mPendingRequests = new ArrayDeque<>(); + final FixedSizeQueue<PendingRequest> mPendingRequests = + new FixedSizeQueue<>(MAX_PENDING_REQUESTS, + request -> { + Slog.w(LOG_TAG, + String.format("Pending request[%s] is dropped", request.mName)); + if (request.mOnServiceFailure != null) { + request.mOnServiceFailure.run(); + } + }); @Nullable @GuardedBy("mLock") ITextClassifierService mService; @@ -910,7 +923,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi pw.printPair("bindServiceFlags", mBindServiceFlags); pw.printPair("boundServiceUid", mBoundServiceUid); pw.printPair("binding", mBinding); - pw.printPair("numberRequests", mPendingRequests.size()); + pw.printPair("numOfPendingRequests", mPendingRequests.size()); } } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 7c935d0ea546..6dd1ea934497 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -1685,6 +1685,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final NeededUriGrants resultGrants = collectGrants(resultData, r.resultTo); synchronized (mGlobalLock) { + // Sanity check in case activity was removed before entering global lock. + if (!r.isInHistory()) { + return true; + } + // Keep track of the root activity of the task before we finish it final Task tr = r.getTask(); final ActivityRecord rootR = tr.getRootActivity(); diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java index 399a00f0cb5a..f205fde88c0d 100644 --- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java @@ -23,7 +23,6 @@ import static org.hamcrest.Matchers.empty; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -58,7 +57,6 @@ import org.junit.runners.JUnit4; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; -import org.mockito.stubbing.Answer; import java.security.cert.CertificateException; import java.util.ArrayList; @@ -71,20 +69,16 @@ import java.util.Set; @RunWith(JUnit4.class) public class AppsFilterTest { - private static final int DUMMY_CALLING_APPID = 10345; - private static final int DUMMY_TARGET_APPID = 10556; - private static final int DUMMY_ACTOR_APPID = 10656; - private static final int DUMMY_OVERLAY_APPID = 10756; - private static final int SYSTEM_USER = 0; - private static final int[] SINGLE_USER_ARRAY = {SYSTEM_USER}; + private static final int DUMMY_CALLING_UID = 10345; + private static final int DUMMY_TARGET_UID = 10556; + private static final int DUMMY_ACTOR_UID = 10656; + private static final int DUMMY_OVERLAY_UID = 10756; + private static final int DUMMY_ACTOR_TWO_UID = 10856; @Mock AppsFilter.FeatureConfig mFeatureConfigMock; - @Mock - AppsFilter.StateProvider mStateProvider; private ArrayMap<String, PackageSetting> mExisting = new ArrayMap<>(); - private Object mDummyLock = new Object(); private static ParsingPackage pkg(String packageName) { return PackageImpl.forTesting(packageName) @@ -176,24 +170,15 @@ public class AppsFilterTest { mExisting = new ArrayMap<>(); MockitoAnnotations.initMocks(this); - doAnswer(invocation -> { - ((AppsFilter.StateProvider.CurrentStateCallback) invocation.getArgument(0)) - .currentState(mExisting, SINGLE_USER_ARRAY); - return null; - }).when(mStateProvider) - .runWithState(any(AppsFilter.StateProvider.CurrentStateCallback.class)); - when(mFeatureConfigMock.isGloballyEnabled()).thenReturn(true); - when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class))).thenAnswer( - (Answer<Boolean>) invocation -> - ((AndroidPackage)invocation.getArgument(SYSTEM_USER)).getTargetSdkVersion() - >= Build.VERSION_CODES.R); + when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class))) + .thenReturn(true); } @Test public void testSystemReadyPropogates() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); appsFilter.onSystemReady(); verify(mFeatureConfigMock).onSystemReady(); } @@ -201,23 +186,22 @@ public class AppsFilterTest { @Test public void testQueriesAction_FilterMatches() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, - pkg("com.some.package", new IntentFilter("TEST_ACTION")), DUMMY_TARGET_APPID); + pkg("com.some.package", new IntentFilter("TEST_ACTION")), DUMMY_TARGET_UID); PackageSetting calling = simulateAddPackage(appsFilter, - pkg("com.some.other.package", new Intent("TEST_ACTION")), DUMMY_CALLING_APPID); + pkg("com.some.other.package", new Intent("TEST_ACTION")), DUMMY_CALLING_UID); - assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, - SYSTEM_USER)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); } @Test public void testQueriesProtectedAction_FilterDoesNotMatch() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); final Signature frameworkSignature = Mockito.mock(Signature.class); final PackageParser.SigningDetails frameworkSigningDetails = new PackageParser.SigningDetails(new Signature[]{frameworkSignature}, 1); @@ -227,174 +211,164 @@ public class AppsFilterTest { b -> b.setSigningDetails(frameworkSigningDetails)); appsFilter.onSystemReady(); - final int activityUid = DUMMY_TARGET_APPID; + final int activityUid = DUMMY_TARGET_UID; PackageSetting targetActivity = simulateAddPackage(appsFilter, pkg("com.target.activity", new IntentFilter("TEST_ACTION")), activityUid); - final int receiverUid = DUMMY_TARGET_APPID + 1; + final int receiverUid = DUMMY_TARGET_UID + 1; PackageSetting targetReceiver = simulateAddPackage(appsFilter, pkgWithReceiver("com.target.receiver", new IntentFilter("TEST_ACTION")), receiverUid); - final int callingUid = DUMMY_CALLING_APPID; + final int callingUid = DUMMY_CALLING_UID; PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.calling.action", new Intent("TEST_ACTION")), callingUid); - final int wildcardUid = DUMMY_CALLING_APPID + 1; + final int wildcardUid = DUMMY_CALLING_UID + 1; PackageSetting callingWildCard = simulateAddPackage(appsFilter, pkg("com.calling.wildcard", new Intent("*")), wildcardUid); - assertFalse(appsFilter.shouldFilterApplication(callingUid, calling, targetActivity, - SYSTEM_USER)); - assertTrue(appsFilter.shouldFilterApplication(callingUid, calling, targetReceiver, - SYSTEM_USER)); + assertFalse(appsFilter.shouldFilterApplication(callingUid, calling, targetActivity, 0)); + assertTrue(appsFilter.shouldFilterApplication(callingUid, calling, targetReceiver, 0)); assertFalse(appsFilter.shouldFilterApplication( - wildcardUid, callingWildCard, targetActivity, SYSTEM_USER)); + wildcardUid, callingWildCard, targetActivity, 0)); assertTrue(appsFilter.shouldFilterApplication( - wildcardUid, callingWildCard, targetReceiver, SYSTEM_USER)); + wildcardUid, callingWildCard, targetReceiver, 0)); } @Test public void testQueriesProvider_FilterMatches() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, - pkgWithProvider("com.some.package", "com.some.authority"), DUMMY_TARGET_APPID); + pkgWithProvider("com.some.package", "com.some.authority"), DUMMY_TARGET_UID); PackageSetting calling = simulateAddPackage(appsFilter, pkgQueriesProvider("com.some.other.package", "com.some.authority"), - DUMMY_CALLING_APPID); + DUMMY_CALLING_UID); - assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, - SYSTEM_USER)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); } @Test public void testQueriesDifferentProvider_Filters() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, - pkgWithProvider("com.some.package", "com.some.authority"), DUMMY_TARGET_APPID); + pkgWithProvider("com.some.package", "com.some.authority"), DUMMY_TARGET_UID); PackageSetting calling = simulateAddPackage(appsFilter, pkgQueriesProvider("com.some.other.package", "com.some.other.authority"), - DUMMY_CALLING_APPID); + DUMMY_CALLING_UID); - assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, - SYSTEM_USER)); + assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); } @Test public void testQueriesProviderWithSemiColon_FilterMatches() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkgWithProvider("com.some.package", "com.some.authority;com.some.other.authority"), - DUMMY_TARGET_APPID); + DUMMY_TARGET_UID); PackageSetting calling = simulateAddPackage(appsFilter, pkgQueriesProvider("com.some.other.package", "com.some.authority"), - DUMMY_CALLING_APPID); + DUMMY_CALLING_UID); - assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, - SYSTEM_USER)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); } @Test public void testQueriesAction_NoMatchingAction_Filters() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, - pkg("com.some.package"), DUMMY_TARGET_APPID); + pkg("com.some.package"), DUMMY_TARGET_UID); PackageSetting calling = simulateAddPackage(appsFilter, - pkg("com.some.other.package", new Intent("TEST_ACTION")), DUMMY_CALLING_APPID); + pkg("com.some.other.package", new Intent("TEST_ACTION")), DUMMY_CALLING_UID); - assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, - SYSTEM_USER)); + assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); } @Test public void testQueriesAction_NoMatchingActionFilterLowSdk_DoesntFilter() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, - pkg("com.some.package"), DUMMY_TARGET_APPID); - ParsingPackage callingPkg = pkg("com.some.other.package", - new Intent("TEST_ACTION")) - .setTargetSdkVersion(Build.VERSION_CODES.P); - PackageSetting calling = simulateAddPackage(appsFilter, callingPkg, - DUMMY_CALLING_APPID); + pkg("com.some.package"), DUMMY_TARGET_UID); + PackageSetting calling = simulateAddPackage(appsFilter, + pkg("com.some.other.package", + new Intent("TEST_ACTION")) + .setTargetSdkVersion(Build.VERSION_CODES.P), + DUMMY_CALLING_UID); + when(mFeatureConfigMock.packageIsEnabled(calling.pkg)).thenReturn(false); - assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, - SYSTEM_USER)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); } @Test public void testNoQueries_Filters() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, - pkg("com.some.package"), DUMMY_TARGET_APPID); + pkg("com.some.package"), DUMMY_TARGET_UID); PackageSetting calling = simulateAddPackage(appsFilter, - pkg("com.some.other.package"), DUMMY_CALLING_APPID); + pkg("com.some.other.package"), DUMMY_CALLING_UID); - assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, - SYSTEM_USER)); + assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); } @Test public void testForceQueryable_DoesntFilter() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, - pkg("com.some.package").setForceQueryable(true), DUMMY_TARGET_APPID); + pkg("com.some.package").setForceQueryable(true), DUMMY_TARGET_UID); PackageSetting calling = simulateAddPackage(appsFilter, - pkg("com.some.other.package"), DUMMY_CALLING_APPID); + pkg("com.some.other.package"), DUMMY_CALLING_UID); - assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, - SYSTEM_USER)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); } @Test public void testForceQueryableByDevice_SystemCaller_DoesntFilter() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{"com.some.package"}, - false, null); + new AppsFilter(mFeatureConfigMock, new String[]{"com.some.package"}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, - pkg("com.some.package"), DUMMY_TARGET_APPID, + pkg("com.some.package"), DUMMY_TARGET_UID, setting -> setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM)); PackageSetting calling = simulateAddPackage(appsFilter, - pkg("com.some.other.package"), DUMMY_CALLING_APPID); + pkg("com.some.other.package"), DUMMY_CALLING_UID); - assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, - SYSTEM_USER)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); } @Test public void testSystemSignedTarget_DoesntFilter() throws CertificateException { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); appsFilter.onSystemReady(); final Signature frameworkSignature = Mockito.mock(Signature.class); @@ -408,67 +382,62 @@ public class AppsFilterTest { simulateAddPackage(appsFilter, pkg("android"), 1000, b -> b.setSigningDetails(frameworkSigningDetails)); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"), - DUMMY_TARGET_APPID, + DUMMY_TARGET_UID, b -> b.setSigningDetails(frameworkSigningDetails) .setPkgFlags(ApplicationInfo.FLAG_SYSTEM)); PackageSetting calling = simulateAddPackage(appsFilter, - pkg("com.some.other.package"), DUMMY_CALLING_APPID, + pkg("com.some.other.package"), DUMMY_CALLING_UID, b -> b.setSigningDetails(otherSigningDetails)); - assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, - SYSTEM_USER)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); } @Test public void testForceQueryableByDevice_NonSystemCaller_Filters() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{"com.some.package"}, - false, null); + new AppsFilter(mFeatureConfigMock, new String[]{"com.some.package"}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, - pkg("com.some.package"), DUMMY_TARGET_APPID); + pkg("com.some.package"), DUMMY_TARGET_UID); PackageSetting calling = simulateAddPackage(appsFilter, - pkg("com.some.other.package"), DUMMY_CALLING_APPID); + pkg("com.some.other.package"), DUMMY_CALLING_UID); - assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, - SYSTEM_USER)); + assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); } @Test public void testSystemQueryable_DoesntFilter() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, + new AppsFilter(mFeatureConfigMock, new String[]{}, true /* system force queryable */, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, - pkg("com.some.package"), DUMMY_TARGET_APPID, + pkg("com.some.package"), DUMMY_TARGET_UID, setting -> setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM)); PackageSetting calling = simulateAddPackage(appsFilter, - pkg("com.some.other.package"), DUMMY_CALLING_APPID); + pkg("com.some.other.package"), DUMMY_CALLING_UID); - assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, - SYSTEM_USER)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); } @Test public void testQueriesPackage_DoesntFilter() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, - pkg("com.some.package"), DUMMY_TARGET_APPID); + pkg("com.some.package"), DUMMY_TARGET_UID); PackageSetting calling = simulateAddPackage(appsFilter, - pkg("com.some.other.package", "com.some.package"), DUMMY_CALLING_APPID); + pkg("com.some.other.package", "com.some.package"), DUMMY_CALLING_UID); - assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, - SYSTEM_USER)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); } @Test @@ -476,67 +445,63 @@ public class AppsFilterTest { when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class))) .thenReturn(false); final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage( - appsFilter, pkg("com.some.package"), DUMMY_TARGET_APPID); + appsFilter, pkg("com.some.package"), DUMMY_TARGET_UID); PackageSetting calling = simulateAddPackage( - appsFilter, pkg("com.some.other.package"), DUMMY_CALLING_APPID); + appsFilter, pkg("com.some.other.package"), DUMMY_CALLING_UID); - assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, - SYSTEM_USER)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); } @Test public void testSystemUid_DoesntFilter() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, - pkg("com.some.package"), DUMMY_TARGET_APPID); + pkg("com.some.package"), DUMMY_TARGET_UID); - assertFalse(appsFilter.shouldFilterApplication(SYSTEM_USER, null, target, SYSTEM_USER)); + assertFalse(appsFilter.shouldFilterApplication(0, null, target, 0)); assertFalse(appsFilter.shouldFilterApplication(Process.FIRST_APPLICATION_UID - 1, - null, target, SYSTEM_USER)); + null, target, 0)); } @Test public void testNonSystemUid_NoCallingSetting_Filters() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, - pkg("com.some.package"), DUMMY_TARGET_APPID); + pkg("com.some.package"), DUMMY_TARGET_UID); - assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, null, target, - SYSTEM_USER)); + assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, null, target, 0)); } @Test public void testNoTargetPackage_filters() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = new PackageSettingBuilder() - .setAppId(DUMMY_TARGET_APPID) .setName("com.some.package") .setCodePath("/") .setResourcePath("/") .setPVersionCode(1L) .build(); PackageSetting calling = simulateAddPackage(appsFilter, - pkg("com.some.other.package", new Intent("TEST_ACTION")), DUMMY_CALLING_APPID); + pkg("com.some.other.package", new Intent("TEST_ACTION")), DUMMY_CALLING_UID); - assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, - SYSTEM_USER)); + assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); } @Test @@ -551,11 +516,7 @@ public class AppsFilterTest { .setOverlayTargetName("overlayableName"); ParsingPackage actor = pkg("com.some.package.actor"); - final AppsFilter appsFilter = new AppsFilter( - mStateProvider, - mFeatureConfigMock, - new String[]{}, - false, + final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, new OverlayReferenceMapper.Provider() { @Nullable @Override @@ -583,34 +544,31 @@ public class AppsFilterTest { simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); - PackageSetting targetSetting = simulateAddPackage(appsFilter, target, DUMMY_TARGET_APPID); - PackageSetting overlaySetting = - simulateAddPackage(appsFilter, overlay, DUMMY_OVERLAY_APPID); - PackageSetting actorSetting = simulateAddPackage(appsFilter, actor, DUMMY_ACTOR_APPID); + PackageSetting targetSetting = simulateAddPackage(appsFilter, target, DUMMY_TARGET_UID); + PackageSetting overlaySetting = simulateAddPackage(appsFilter, overlay, DUMMY_OVERLAY_UID); + PackageSetting actorSetting = simulateAddPackage(appsFilter, actor, DUMMY_ACTOR_UID); // Actor can see both target and overlay - assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_APPID, actorSetting, - targetSetting, SYSTEM_USER)); - assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_APPID, actorSetting, - overlaySetting, SYSTEM_USER)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_UID, actorSetting, + targetSetting, 0)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_UID, actorSetting, + overlaySetting, 0)); // But target/overlay can't see each other - assertTrue(appsFilter.shouldFilterApplication(DUMMY_TARGET_APPID, targetSetting, - overlaySetting, SYSTEM_USER)); - assertTrue(appsFilter.shouldFilterApplication(DUMMY_OVERLAY_APPID, overlaySetting, - targetSetting, SYSTEM_USER)); + assertTrue(appsFilter.shouldFilterApplication(DUMMY_TARGET_UID, targetSetting, + overlaySetting, 0)); + assertTrue(appsFilter.shouldFilterApplication(DUMMY_OVERLAY_UID, overlaySetting, + targetSetting, 0)); // And can't see the actor - assertTrue(appsFilter.shouldFilterApplication(DUMMY_TARGET_APPID, targetSetting, - actorSetting, SYSTEM_USER)); - assertTrue(appsFilter.shouldFilterApplication(DUMMY_OVERLAY_APPID, overlaySetting, - actorSetting, SYSTEM_USER)); + assertTrue(appsFilter.shouldFilterApplication(DUMMY_TARGET_UID, targetSetting, + actorSetting, 0)); + assertTrue(appsFilter.shouldFilterApplication(DUMMY_OVERLAY_UID, overlaySetting, + actorSetting, 0)); } @Test public void testActsOnTargetOfOverlayThroughSharedUser() throws Exception { -// Debug.waitForDebugger(); - final String actorName = "overlay://test/actorName"; ParsingPackage target = pkg("com.some.package.target") @@ -622,11 +580,7 @@ public class AppsFilterTest { ParsingPackage actorOne = pkg("com.some.package.actor.one"); ParsingPackage actorTwo = pkg("com.some.package.actor.two"); - final AppsFilter appsFilter = new AppsFilter( - mStateProvider, - mFeatureConfigMock, - new String[]{}, - false, + final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, new OverlayReferenceMapper.Provider() { @Nullable @Override @@ -655,114 +609,108 @@ public class AppsFilterTest { simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); - PackageSetting targetSetting = simulateAddPackage(appsFilter, target, DUMMY_TARGET_APPID); - SharedUserSetting actorSharedSetting = new SharedUserSetting("actorSharedUser", - targetSetting.pkgFlags, targetSetting.pkgPrivateFlags); - PackageSetting overlaySetting = - simulateAddPackage(appsFilter, overlay, DUMMY_OVERLAY_APPID); - simulateAddPackage(appsFilter, actorOne, DUMMY_ACTOR_APPID, - null /*settingBuilder*/, actorSharedSetting); - simulateAddPackage(appsFilter, actorTwo, DUMMY_ACTOR_APPID, - null /*settingBuilder*/, actorSharedSetting); + PackageSetting targetSetting = simulateAddPackage(appsFilter, target, DUMMY_TARGET_UID); + PackageSetting overlaySetting = simulateAddPackage(appsFilter, overlay, DUMMY_OVERLAY_UID); + PackageSetting actorOneSetting = simulateAddPackage(appsFilter, actorOne, DUMMY_ACTOR_UID); + PackageSetting actorTwoSetting = simulateAddPackage(appsFilter, actorTwo, + DUMMY_ACTOR_TWO_UID); + SharedUserSetting actorSharedSetting = new SharedUserSetting("actorSharedUser", + actorOneSetting.pkgFlags, actorOneSetting.pkgPrivateFlags); + actorSharedSetting.addPackage(actorOneSetting); + actorSharedSetting.addPackage(actorTwoSetting); // actorTwo can see both target and overlay - assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_APPID, actorSharedSetting, - targetSetting, SYSTEM_USER)); - assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_APPID, actorSharedSetting, - overlaySetting, SYSTEM_USER)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_TWO_UID, actorSharedSetting, + targetSetting, 0)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_TWO_UID, actorSharedSetting, + overlaySetting, 0)); } @Test public void testInitiatingApp_DoesntFilter() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"), - DUMMY_TARGET_APPID); + DUMMY_TARGET_UID); PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package"), - DUMMY_CALLING_APPID, withInstallSource(target.name, null, null, false)); + DUMMY_CALLING_UID, withInstallSource(target.name, null, null, false)); - assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, - SYSTEM_USER)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); } @Test public void testUninstalledInitiatingApp_Filters() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"), - DUMMY_TARGET_APPID); + DUMMY_TARGET_UID); PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package"), - DUMMY_CALLING_APPID, withInstallSource(target.name, null, null, true)); + DUMMY_CALLING_UID, withInstallSource(target.name, null, null, true)); - assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, - SYSTEM_USER)); + assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); } @Test public void testOriginatingApp_Filters() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"), - DUMMY_TARGET_APPID); + DUMMY_TARGET_UID); PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package"), - DUMMY_CALLING_APPID, withInstallSource(null, target.name, null, false)); + DUMMY_CALLING_UID, withInstallSource(null, target.name, null, false)); - assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, - SYSTEM_USER)); + assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); } @Test public void testInstallingApp_DoesntFilter() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"), - DUMMY_TARGET_APPID); + DUMMY_TARGET_UID); PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package"), - DUMMY_CALLING_APPID, withInstallSource(null, null, target.name, false)); + DUMMY_CALLING_UID, withInstallSource(null, null, target.name, false)); - assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, - SYSTEM_USER)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); } @Test public void testInstrumentation_DoesntFilter() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"), - DUMMY_TARGET_APPID); + DUMMY_TARGET_UID); PackageSetting instrumentation = simulateAddPackage(appsFilter, pkgWithInstrumentation("com.some.other.package", "com.some.package"), - DUMMY_CALLING_APPID); + DUMMY_CALLING_UID); assertFalse( - appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, instrumentation, target, - SYSTEM_USER)); + appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, instrumentation, target, 0)); assertFalse( - appsFilter.shouldFilterApplication(DUMMY_TARGET_APPID, target, instrumentation, - SYSTEM_USER)); + appsFilter.shouldFilterApplication(DUMMY_TARGET_UID, target, instrumentation, 0)); } @Test public void testWhoCanSee() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); @@ -780,25 +728,21 @@ public class AppsFilterTest { queriesProviderAppId); final int[] systemFilter = - appsFilter.getVisibilityWhitelist(system, SINGLE_USER_ARRAY, mExisting) - .get(SYSTEM_USER); + appsFilter.getVisibilityWhitelist(system, new int[]{0}, mExisting).get(0); assertThat(toList(systemFilter), empty()); final int[] seesNothingFilter = - appsFilter.getVisibilityWhitelist(seesNothing, SINGLE_USER_ARRAY, mExisting) - .get(SYSTEM_USER); + appsFilter.getVisibilityWhitelist(seesNothing, new int[]{0}, mExisting).get(0); assertThat(toList(seesNothingFilter), contains(seesNothingAppId)); final int[] hasProviderFilter = - appsFilter.getVisibilityWhitelist(hasProvider, SINGLE_USER_ARRAY, mExisting) - .get(SYSTEM_USER); + appsFilter.getVisibilityWhitelist(hasProvider, new int[]{0}, mExisting).get(0); assertThat(toList(hasProviderFilter), contains(hasProviderAppId, queriesProviderAppId)); int[] queriesProviderFilter = - appsFilter.getVisibilityWhitelist(queriesProvider, SINGLE_USER_ARRAY, mExisting) - .get(SYSTEM_USER); + appsFilter.getVisibilityWhitelist(queriesProvider, new int[]{0}, mExisting).get(0); assertThat(toList(queriesProviderFilter), contains(queriesProviderAppId)); @@ -807,8 +751,7 @@ public class AppsFilterTest { // ensure implicit access is included in the filter queriesProviderFilter = - appsFilter.getVisibilityWhitelist(queriesProvider, SINGLE_USER_ARRAY, mExisting) - .get(SYSTEM_USER); + appsFilter.getVisibilityWhitelist(queriesProvider, new int[]{0}, mExisting).get(0); assertThat(toList(queriesProviderFilter), contains(hasProviderAppId, queriesProviderAppId)); } @@ -836,17 +779,11 @@ public class AppsFilterTest { private PackageSetting simulateAddPackage(AppsFilter filter, ParsingPackage newPkgBuilder, int appId) { - return simulateAddPackage(filter, newPkgBuilder, appId, null /*settingBuilder*/); + return simulateAddPackage(filter, newPkgBuilder, appId, null); } private PackageSetting simulateAddPackage(AppsFilter filter, ParsingPackage newPkgBuilder, int appId, @Nullable WithSettingBuilder action) { - return simulateAddPackage(filter, newPkgBuilder, appId, action, null /*sharedUserSetting*/); - } - - private PackageSetting simulateAddPackage(AppsFilter filter, - ParsingPackage newPkgBuilder, int appId, @Nullable WithSettingBuilder action, - @Nullable SharedUserSetting sharedUserSetting) { AndroidPackage newPkg = ((ParsedPackage) newPkgBuilder.hideAsParsed()).hideAsFinal(); final PackageSettingBuilder settingBuilder = new PackageSettingBuilder() @@ -858,12 +795,8 @@ public class AppsFilterTest { .setPVersionCode(1L); final PackageSetting setting = (action == null ? settingBuilder : action.withBuilder(settingBuilder)).build(); + filter.addPackage(setting, mExisting); mExisting.put(newPkg.getPackageName(), setting); - if (sharedUserSetting != null) { - sharedUserSetting.addPackage(setting); - setting.sharedUser = sharedUserSetting; - } - filter.addPackage(setting); return setting; } @@ -876,3 +809,4 @@ public class AppsFilterTest { return setting -> setting.setInstallSource(installSource); } } + diff --git a/services/tests/servicestests/src/com/android/server/textclassifier/FixedSizeQueueTest.java b/services/tests/servicestests/src/com/android/server/textclassifier/FixedSizeQueueTest.java new file mode 100644 index 000000000000..90527b82c2c3 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/textclassifier/FixedSizeQueueTest.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.textclassifier; + +import static com.google.common.truth.Truth.assertThat; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +public class FixedSizeQueueTest { + + @Test + public void add_belowMaxCapacity() { + FixedSizeQueue<Integer> queue = new FixedSizeQueue<>(1, /* onEntryEvictedListener= */ null); + assertThat(queue.size()).isEqualTo(0); + + queue.add(1); + + assertThat(queue.size()).isEqualTo(1); + assertThat(queue.poll()).isEqualTo(1); + } + + @Test + public void add_exceedMaxCapacity() { + FixedSizeQueue<Integer> queue = new FixedSizeQueue<>(2, /* onEntryEvictedListener= */ null); + + queue.add(1); + queue.add(2); + queue.add(3); + + assertThat(queue.size()).isEqualTo(2); + assertThat(queue.poll()).isEqualTo(2); + assertThat(queue.poll()).isEqualTo(3); + } + + @Test + public void poll() { + FixedSizeQueue<Integer> queue = new FixedSizeQueue<>(1, /* onEntryEvictedListener= */ null); + + queue.add(1); + + assertThat(queue.poll()).isEqualTo(1); + assertThat(queue.poll()).isNull(); + } + + @Test + public void remove() { + FixedSizeQueue<Integer> queue = new FixedSizeQueue<>(1, /* onEntryEvictedListener= */ null); + + queue.add(1); + + assertThat(queue.remove(1)).isTrue(); + assertThat(queue.isEmpty()).isTrue(); + } + + @Test + public void remove_noSuchElement() { + FixedSizeQueue<Integer> queue = new FixedSizeQueue<>(1, /* onEntryEvictedListener= */ null); + + queue.add(1); + + assertThat(queue.remove(2)).isFalse(); + } + + @Test + public void isEmpty_true() { + FixedSizeQueue<Integer> queue = new FixedSizeQueue<>(1, /* onEntryEvictedListener= */ null); + + assertThat(queue.isEmpty()).isTrue(); + } + + @Test + public void isEmpty_false() { + FixedSizeQueue<Integer> queue = new FixedSizeQueue<>(1, /* onEntryEvictedListener= */ null); + + queue.add(1); + + assertThat(queue.isEmpty()).isFalse(); + } + + @Test + public void onEntryEvicted() { + List<Integer> onEntryEvictedElements = new ArrayList<>(); + FixedSizeQueue<Integer> queue = + new FixedSizeQueue<>(1, onEntryEvictedElements::add); + + queue.add(1); + queue.add(2); + queue.add(3); + + assertThat(onEntryEvictedElements).containsExactly(1, 2).inOrder(); + } +} 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 be3c4eeeaec2..ef4d5db2f32f 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -178,6 +178,7 @@ import com.android.server.wm.WindowManagerInternal; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -1338,6 +1339,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + @Ignore public void testPostCancelPostNotifiesListeners() throws Exception { // WHEN a notification is posted final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); diff --git a/telephony/common/com/android/internal/telephony/CarrierAppUtils.java b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java index b3d7c0d36763..4606fb4b631c 100644 --- a/telephony/common/com/android/internal/telephony/CarrierAppUtils.java +++ b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java @@ -21,7 +21,6 @@ import android.content.ContentResolver; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; -import android.content.res.Resources; import android.os.SystemConfigManager; import android.os.UserHandle; import android.permission.PermissionManager; @@ -30,9 +29,7 @@ import android.telephony.TelephonyManager; import android.util.ArrayMap; import android.util.Log; -import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.telephony.util.ArrayUtils; import java.util.ArrayList; import java.util.List; @@ -162,12 +159,9 @@ public final class CarrierAppUtils { try { for (ApplicationInfo ai : candidates) { String packageName = ai.packageName; - String[] restrictedCarrierApps = Resources.getSystem().getStringArray( - R.array.config_restrictedPreinstalledCarrierApps); boolean hasPrivileges = telephonyManager != null && telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName) - == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS - && !ArrayUtils.contains(restrictedCarrierApps, packageName); + == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; // add hiddenUntilInstalled flag for carrier apps and associated apps packageManager.setSystemAppState( diff --git a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt b/tests/net/common/java/android/net/NetworkAgentConfigTest.kt index de65ba24972b..a4d8353d1253 100644 --- a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt +++ b/tests/net/common/java/android/net/NetworkAgentConfigTest.kt @@ -44,7 +44,7 @@ class NetworkAgentConfigTest { setPartialConnectivityAcceptable(false) setUnvalidatedConnectivityAcceptable(true) }.build() - assertParcelSane(config, 9) + assertParcelSane(config, 10) } @Test @IgnoreUpTo(Build.VERSION_CODES.Q) |