diff options
212 files changed, 3136 insertions, 4288 deletions
diff --git a/StubLibraries.bp b/StubLibraries.bp index 6927f4449054..0f805655b33d 100644 --- a/StubLibraries.bp +++ b/StubLibraries.bp @@ -340,7 +340,7 @@ java_library_static { } java_library_static { - name: "framework_module_app_stubs_current", + name: "android_module_app_stubs_current", srcs: [ ":module-app-api-stubs-docs", ], @@ -355,7 +355,7 @@ java_library_static { } java_library_static { - name: "framework_module_lib_stubs_current", + name: "android_module_lib_stubs_current", srcs: [ ":module-lib-api-stubs-docs", ], diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java index ed5626a1acbc..69f4748548a7 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -77,7 +77,6 @@ import android.util.Log; import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; -import android.util.StatsLog; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; @@ -85,6 +84,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IBatteryStats; import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; +import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.IndentingPrintWriter; import com.android.server.AppStateTracker; import com.android.server.DeviceIdleInternal; @@ -1171,9 +1171,9 @@ public class JobSchedulerService extends com.android.server.SystemService jobStatus.enqueueWorkLocked(work); } - StatsLog.write_non_chained(StatsLog.SCHEDULED_JOB_STATE_CHANGED, + FrameworkStatsLog.write_non_chained(FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED, uId, null, jobStatus.getBatteryName(), - StatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__SCHEDULED, + FrameworkStatsLog.SCHEDULED_JOB_STATE_CHANGED__STATE__SCHEDULED, JobProtoEnums.STOP_REASON_CANCELLED, jobStatus.getStandbyBucket(), jobStatus.getJobId()); @@ -2567,7 +2567,8 @@ public class JobSchedulerService extends com.android.server.SystemService BatteryStatsInternal mBatteryStatsInternal = LocalServices.getService (BatteryStatsInternal.class); mBatteryStatsInternal.noteJobsDeferred(uid, counter.numDeferred(), sinceLast); - StatsLog.write_non_chained(StatsLog.DEFERRED_JOB_STATS_REPORTED, uid, null, + FrameworkStatsLog.write_non_chained( + FrameworkStatsLog.DEFERRED_JOB_STATS_REPORTED, uid, null, counter.numDeferred(), sinceLast); } } diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java index dbdce70dda03..f706260edec2 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java @@ -32,10 +32,10 @@ import android.text.format.DateFormat; import android.util.ArraySet; import android.util.Pair; import android.util.Slog; -import android.util.StatsLog; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; +import com.android.internal.util.FrameworkStatsLog; import com.android.server.LocalServices; import com.android.server.job.GrantedUriPermissions; import com.android.server.job.JobSchedulerInternal; @@ -1059,10 +1059,12 @@ public final class JobStatus { mReadyDynamicSatisfied = mDynamicConstraints == (satisfiedConstraints & mDynamicConstraints); if (STATS_LOG_ENABLED && (STATSD_CONSTRAINTS_TO_LOG & constraint) != 0) { - StatsLog.write_non_chained(StatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED, + FrameworkStatsLog.write_non_chained( + FrameworkStatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED, sourceUid, null, getBatteryName(), getProtoConstraint(constraint), - state ? StatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED__STATE__SATISFIED - : StatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED__STATE__UNSATISFIED); + state ? FrameworkStatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED__STATE__SATISFIED + : FrameworkStatsLog + .SCHEDULED_JOB_CONSTRAINT_CHANGED__STATE__UNSATISFIED); } return true; } diff --git a/apex/statsd/framework/Android.bp b/apex/statsd/framework/Android.bp index f66f0340edab..231c91026bb6 100644 --- a/apex/statsd/framework/Android.bp +++ b/apex/statsd/framework/Android.bp @@ -34,9 +34,8 @@ java_library { ], libs: [ "framework-annotations-lib", - // TODO(b/146230220): Use framework-system-stubs instead. - //"android_system_stubs_current", - //"framework_module_lib_stubs_current", + // TODO(b/146230220): Use android_module_lib_stubs_current instead. + //"android_module_lib_stubs_current", "framework-all", ], hostdex: true, // for hiddenapi check diff --git a/api/current.txt b/api/current.txt index 32fb1e7e8bfd..510db01940cd 100644 --- a/api/current.txt +++ b/api/current.txt @@ -47070,8 +47070,8 @@ package android.telephony { } public class MmsManager { - method public void downloadMultimediaMessage(int, @NonNull String, @NonNull android.net.Uri, @Nullable android.os.Bundle, @Nullable android.app.PendingIntent); - method public void sendMultimediaMessage(int, @NonNull android.net.Uri, @Nullable String, @Nullable android.os.Bundle, @Nullable android.app.PendingIntent); + method public void downloadMultimediaMessage(int, @NonNull String, @NonNull android.net.Uri, @Nullable android.os.Bundle, @Nullable android.app.PendingIntent, long); + method public void sendMultimediaMessage(int, @NonNull android.net.Uri, @Nullable String, @Nullable android.os.Bundle, @Nullable android.app.PendingIntent, long); } @Deprecated public class NeighboringCellInfo implements android.os.Parcelable { @@ -51776,7 +51776,7 @@ package android.view { method public int getFlags(); method public android.view.Display.HdrCapabilities getHdrCapabilities(); method @Deprecated public int getHeight(); - method public void getMetrics(android.util.DisplayMetrics); + method @Deprecated public void getMetrics(android.util.DisplayMetrics); method public android.view.Display.Mode getMode(); method public String getName(); method @Deprecated public int getOrientation(); @@ -51785,10 +51785,10 @@ package android.view { method public long getPresentationDeadlineNanos(); method public void getRealMetrics(android.util.DisplayMetrics); method public void getRealSize(android.graphics.Point); - method public void getRectSize(android.graphics.Rect); + method @Deprecated public void getRectSize(android.graphics.Rect); method public float getRefreshRate(); method public int getRotation(); - method public void getSize(android.graphics.Point); + method @Deprecated public void getSize(android.graphics.Point); method public int getState(); method public android.view.Display.Mode[] getSupportedModes(); method @Deprecated public float[] getSupportedRefreshRates(); diff --git a/api/system-current.txt b/api/system-current.txt index e3c61c89dcb9..0930f68e7b1a 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -7580,7 +7580,7 @@ package android.net.wifi { method public boolean isEphemeral(); method public boolean isOsuAp(); method public boolean isPasspointAp(); - method @Nullable public static String removeDoubleQuotes(@Nullable String); + method @Nullable public static String sanitizeSsid(@Nullable String); field public static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00"; field public static final int INVALID_RSSI = -127; // 0xffffff81 } @@ -7622,7 +7622,6 @@ package android.net.wifi { method public boolean isApMacRandomizationSupported(); method public boolean isConnectedMacRandomizationSupported(); method @Deprecated public boolean isDeviceToDeviceRttSupported(); - method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public boolean isDualModeSupported(); method public boolean isPortableHotspotSupported(); method public boolean isVerboseLoggingEnabled(); method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isWifiApEnabled(); @@ -8962,7 +8961,6 @@ package android.os { method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isSameProfileGroup(@NonNull android.os.UserHandle, @NonNull android.os.UserHandle); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}) public boolean isUserNameSet(); method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isUserOfType(@NonNull String); - method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isUserOfType(@NonNull android.os.UserHandle, @NonNull String); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isUserUnlockingOrUnlocked(@NonNull android.os.UserHandle); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean removeUser(@NonNull android.os.UserHandle); method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserIcon(@NonNull android.graphics.Bitmap) throws android.os.UserManager.UserOperationException; diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index fa307bda9d26..7f00410ac9ab 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -226,12 +226,12 @@ message Atom { GnssNfwNotificationReported gnss_nfw_notification_reported = 131 [(module) = "framework"]; GnssConfigurationReported gnss_configuration_reported = 132 [(module) = "framework"]; UsbPortOverheatEvent usb_port_overheat_event_reported = 133; - NfcErrorOccurred nfc_error_occurred = 134; - NfcStateChanged nfc_state_changed = 135; - NfcBeamOccurred nfc_beam_occurred = 136; - NfcCardemulationOccurred nfc_cardemulation_occurred = 137; - NfcTagOccurred nfc_tag_occurred = 138; - NfcHceTransactionOccurred nfc_hce_transaction_occurred = 139; + NfcErrorOccurred nfc_error_occurred = 134 [(module) = "nfc"]; + NfcStateChanged nfc_state_changed = 135 [(module) = "nfc"]; + NfcBeamOccurred nfc_beam_occurred = 136 [(module) = "nfc"]; + NfcCardemulationOccurred nfc_cardemulation_occurred = 137 [(module) = "nfc"]; + NfcTagOccurred nfc_tag_occurred = 138 [(module) = "nfc"]; + NfcHceTransactionOccurred nfc_hce_transaction_occurred = 139 [(module) = "nfc"]; SeStateChanged se_state_changed = 140; SeOmapiReported se_omapi_reported = 141; BroadcastDispatchLatencyReported broadcast_dispatch_latency_reported = diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 5f3bad6ad1a8..cb6a476fb617 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -287,7 +287,7 @@ interface IActivityManager { void killApplicationProcess(in String processName, int uid); // Special low-level communication with activity manager. boolean handleApplicationWtf(in IBinder app, in String tag, boolean system, - in ApplicationErrorReport.ParcelableCrashInfo crashInfo); + in ApplicationErrorReport.ParcelableCrashInfo crashInfo, int immediateCallerPid); @UnsupportedAppUsage void killBackgroundProcesses(in String packageName, int userId); boolean isUserAMonkey(); diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 35d26aba9094..576b56fa33f6 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -2487,6 +2487,20 @@ public class Notification implements Parcelable if (extras.containsKey(EXTRA_BACKGROUND_IMAGE_URI)) { visitor.accept(Uri.parse(extras.getString(EXTRA_BACKGROUND_IMAGE_URI))); } + + ArrayList<Person> people = extras.getParcelableArrayList(EXTRA_PEOPLE_LIST); + if (people != null && !people.isEmpty()) { + for (Person p : people) { + if (p.getIconUri() != null) { + visitor.accept(p.getIconUri()); + } + } + } + + final Person person = extras.getParcelable(EXTRA_MESSAGING_PERSON); + if (person != null && person.getIconUri() != null) { + visitor.accept(person.getIconUri()); + } } if (MessagingStyle.class.equals(getNotificationStyle()) && extras != null) { @@ -2495,6 +2509,11 @@ public class Notification implements Parcelable for (MessagingStyle.Message message : MessagingStyle.Message .getMessagesFromBundleArray(messages)) { visitor.accept(message.getDataUri()); + + Person senderPerson = message.getSenderPerson(); + if (senderPerson != null && senderPerson.getIconUri() != null) { + visitor.accept(senderPerson.getIconUri()); + } } } @@ -2503,6 +2522,11 @@ public class Notification implements Parcelable for (MessagingStyle.Message message : MessagingStyle.Message .getMessagesFromBundleArray(historic)) { visitor.accept(message.getDataUri()); + + Person senderPerson = message.getSenderPerson(); + if (senderPerson != null && senderPerson.getIconUri() != null) { + visitor.accept(senderPerson.getIconUri()); + } } } } diff --git a/core/java/android/app/Person.java b/core/java/android/app/Person.java index 14a5589c04c2..63ef2484ca1d 100644 --- a/core/java/android/app/Person.java +++ b/core/java/android/app/Person.java @@ -19,6 +19,7 @@ package android.app; import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.drawable.Icon; +import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; @@ -122,6 +123,20 @@ public final class Person implements Parcelable { return ""; } + /** + * @return the URI associated with the {@link #getIcon()} for this person, iff the icon exists + * and is URI based. + * @hide + */ + @Nullable + public Uri getIconUri() { + if (mIcon != null && (mIcon.getType() == Icon.TYPE_URI + || mIcon.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP)) { + return mIcon.getUri(); + } + return null; + } + @Override public boolean equals(Object obj) { if (obj instanceof Person) { diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java index 736efb6a5e69..cbd2f1a52c0c 100644 --- a/core/java/android/app/PropertyInvalidatedCache.java +++ b/core/java/android/app/PropertyInvalidatedCache.java @@ -297,9 +297,10 @@ public abstract class PropertyInvalidatedCache<Query, Result> { if (currentNonce == NONCE_DISABLED || currentNonce == NONCE_UNSET) { if (DEBUG) { Log.d(TAG, - String.format("cache %s for %s", + String.format("cache %s %s for %s", + cacheName(), currentNonce == NONCE_DISABLED ? "disabled" : "unset", - query)); + queryToString(query))); } return recompute(query); } @@ -310,7 +311,8 @@ public abstract class PropertyInvalidatedCache<Query, Result> { } else { if (DEBUG) { Log.d(TAG, - String.format("clearing cache because nonce changed [%s] -> [%s]", + String.format("clearing cache %s because nonce changed [%s] -> [%s]", + cacheName(), mLastSeenNonce, currentNonce)); } mCache.clear(); @@ -328,13 +330,15 @@ public abstract class PropertyInvalidatedCache<Query, Result> { final Result refreshedResult = refresh(cachedResult, query); if (refreshedResult != cachedResult) { if (DEBUG) { - Log.d(TAG, "cache refresh for " + query); + Log.d(TAG, "cache refresh for " + cacheName() + " " + queryToString(query)); } final long afterRefreshNonce = getCurrentNonce(); if (currentNonce != afterRefreshNonce) { currentNonce = afterRefreshNonce; if (DEBUG) { - Log.d(TAG, "restarting query because nonce changed in refresh"); + Log.d(TAG, String.format("restarting %s %s because nonce changed in refresh", + cacheName(), + queryToString(query))); } continue; } @@ -352,13 +356,13 @@ public abstract class PropertyInvalidatedCache<Query, Result> { return maybeCheckConsistency(query, refreshedResult); } if (DEBUG) { - Log.d(TAG, "cache hit for " + query); + Log.d(TAG, "cache hit for " + cacheName() + " " + queryToString(query)); } return maybeCheckConsistency(query, cachedResult); } // Cache miss: make the value from scratch. if (DEBUG) { - Log.d(TAG, "cache miss for " + query); + Log.d(TAG, "cache miss for " + cacheName() + " " + queryToString(query)); } final Result result = recompute(query); synchronized (mLock) { @@ -451,4 +455,20 @@ public abstract class PropertyInvalidatedCache<Query, Result> { } return proposedResult; } + + /** + * Return the name of the cache, to be used in debug messages. The + * method is public so clients can use it. + */ + public String cacheName() { + return mPropertyName; + } + + /** + * Return the query as a string, to be used in debug messages. The + * method is public so clients can use it in external debug messages. + */ + public String queryToString(Query query) { + return Objects.toString(query); + } } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index d1b5a83e7142..f71d78b40242 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -7028,21 +7028,28 @@ public class DevicePolicyManager { } /** - * Called by a device owner to set the default SMS application. + * Must be called by a device owner or a profile owner of an organization-owned managed profile + * to set the default SMS application. * <p> - * The calling device admin must be a device owner. If it is not, a security exception will be - * thrown. + * This method can be called on the {@link DevicePolicyManager} instance, returned by + * {@link #getParentProfileInstance(ComponentName)}, where the caller must be the profile owner + * of an organization-owned managed profile and the package must be a pre-installed system + * package. If called on the parent instance, then the default SMS application is set on the + * personal profile. * - * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param packageName The name of the package to set as the default SMS application. - * @throws SecurityException if {@code admin} is not a device owner. + * @throws SecurityException if {@code admin} is not a device or profile owner or if + * called on the parent profile and the {@code admin} is not a + * profile owner of an organization-owned managed profile. + * @throws IllegalArgumentException if called on the parent profile and the package + * provided is not a pre-installed system package. */ public void setDefaultSmsApplication(@NonNull ComponentName admin, @NonNull String packageName) { - throwIfParentInstance("setDefaultSmsApplication"); if (mService != null) { try { - mService.setDefaultSmsApplication(admin, packageName); + mService.setDefaultSmsApplication(admin, packageName, mParentInstance); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index e3dba310ab44..7fd0ae4a1a00 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -202,7 +202,7 @@ interface IDevicePolicyManager { void addPersistentPreferredActivity(in ComponentName admin, in IntentFilter filter, in ComponentName activity); void clearPackagePersistentPreferredActivities(in ComponentName admin, String packageName); - void setDefaultSmsApplication(in ComponentName admin, String packageName); + void setDefaultSmsApplication(in ComponentName admin, String packageName, boolean parent); void setApplicationRestrictions(in ComponentName who, in String callerPackage, in String packageName, in Bundle settings); Bundle getApplicationRestrictions(in ComponentName who, in String callerPackage, in String packageName); diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java index 01800c6751fb..14442a2088cd 100644 --- a/core/java/android/net/NetworkPolicyManager.java +++ b/core/java/android/net/NetworkPolicyManager.java @@ -539,13 +539,13 @@ public class NetworkPolicyManager { /** @hide */ public static String resolveNetworkId(WifiConfiguration config) { - return WifiInfo.removeDoubleQuotes(config.isPasspoint() + return WifiInfo.sanitizeSsid(config.isPasspoint() ? config.providerFriendlyName : config.SSID); } /** @hide */ public static String resolveNetworkId(String ssid) { - return WifiInfo.removeDoubleQuotes(ssid); + return WifiInfo.sanitizeSsid(ssid); } /** @hide */ diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 5e6c47a47a8e..5498f74ba2cc 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -32,7 +32,7 @@ import static android.net.NetworkStats.METERED_YES; import static android.net.NetworkStats.ROAMING_ALL; import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.ROAMING_YES; -import static android.net.wifi.WifiInfo.removeDoubleQuotes; +import static android.net.wifi.WifiInfo.sanitizeSsid; import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; @@ -401,7 +401,7 @@ public class NetworkTemplate implements Parcelable { switch (ident.mType) { case TYPE_WIFI: return Objects.equals( - removeDoubleQuotes(mNetworkId), removeDoubleQuotes(ident.mNetworkId)); + sanitizeSsid(mNetworkId), sanitizeSsid(ident.mNetworkId)); default: return false; } diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 3564589e35a4..6ed1d2c345f8 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -1775,9 +1775,10 @@ public class UserManager { } /** - * Returns whether the context user's user is of the given user type, such as - * {@link UserManager#USER_TYPE_FULL_GUEST}. + * Returns whether the context user is of the given user type. * + * @param userType the name of the user's user type, e.g. + * {@link UserManager#USER_TYPE_PROFILE_MANAGED}. * @return true if the user is of the given user type. * @hide */ @@ -1793,26 +1794,6 @@ public class UserManager { } /** - * Returns whether the given user is of the given user type, such as - * {@link UserManager#USER_TYPE_FULL_GUEST}. - * - * @param userHandle the user handle of the user whose type is being requested. - * @param userType the name of the user's user type, e.g. - * {@link UserManager#USER_TYPE_PROFILE_MANAGED}. - * @return true if the userHandle user is of type userType - * @hide - */ - @SystemApi - @RequiresPermission(android.Manifest.permission.MANAGE_USERS) - public boolean isUserOfType(@NonNull UserHandle userHandle, @NonNull String userType) { - try { - return mService.isUserOfType(userHandle.getIdentifier(), userType); - } catch (RemoteException re) { - throw re.rethrowFromSystemServer(); - } - } - - /** * Returns whether the user type is a * {@link UserManager#USER_TYPE_PROFILE_MANAGED managed profile}. * @hide diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 9666c12699e8..605c585215a6 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -8711,6 +8711,14 @@ public final class Settings { "back_gesture_inset_scale_right"; /** + * Current provider of proximity-based sharing services. + * Default value in @string/config_defaultNearbySharingComponent. + * No VALIDATOR as this setting will not be backed up. + * @hide + */ + public static final String NEARBY_SHARING_COMPONENT = "nearby_sharing_component"; + + /** * Controls whether aware is enabled. * @hide */ diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java index c5d97b718ff0..74b913645ad4 100644 --- a/core/java/android/service/notification/StatusBarNotification.java +++ b/core/java/android/service/notification/StatusBarNotification.java @@ -35,6 +35,7 @@ import android.os.Parcelable; import android.os.UserHandle; import android.text.TextUtils; +import com.android.internal.logging.InstanceId; import com.android.internal.logging.nano.MetricsProto; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; @@ -68,6 +69,8 @@ public class StatusBarNotification implements Parcelable { private final UserHandle user; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final long postTime; + // A small per-notification ID, used for statsd logging. + private InstanceId mInstanceId; // Not final, see setInstanceId() private Context mContext; // used for inflation & icon expansion @@ -131,8 +134,9 @@ public class StatusBarNotification implements Parcelable { this.postTime = in.readLong(); if (in.readInt() != 0) { this.overrideGroupKey = in.readString(); - } else { - this.overrideGroupKey = null; + } + if (in.readInt() != 0) { + this.mInstanceId = InstanceId.CREATOR.createFromParcel(in); } this.key = key(); this.groupKey = groupKey(); @@ -196,7 +200,6 @@ public class StatusBarNotification implements Parcelable { out.writeInt(this.initialPid); this.notification.writeToParcel(out, flags); user.writeToParcel(out, flags); - out.writeLong(this.postTime); if (this.overrideGroupKey != null) { out.writeInt(1); @@ -204,6 +207,12 @@ public class StatusBarNotification implements Parcelable { } else { out.writeInt(0); } + if (this.mInstanceId != null) { + out.writeInt(1); + mInstanceId.writeToParcel(out, flags); + } else { + out.writeInt(0); + } } public int describeContents() { @@ -390,6 +399,20 @@ public class StatusBarNotification implements Parcelable { /** * @hide */ + public InstanceId getInstanceId() { + return mInstanceId; + } + + /** + * @hide + */ + public void setInstanceId(InstanceId instanceId) { + mInstanceId = instanceId; + } + + /** + * @hide + */ @UnsupportedAppUsage public Context getPackageContext(Context context) { if (mContext == null) { diff --git a/core/java/android/service/quickaccesswallet/TEST_MAPPING b/core/java/android/service/quickaccesswallet/TEST_MAPPING new file mode 100644 index 000000000000..4d97ab6e612d --- /dev/null +++ b/core/java/android/service/quickaccesswallet/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "CtsQuickAccessWalletTestCases" + } + ] +} diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 0304328f734a..d79fc9a48116 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -57,8 +57,8 @@ import java.util.List; * <li>The application display area specifies the part of the display that may contain * an application window, excluding the system decorations. The application display area may * be smaller than the real display area because the system subtracts the space needed - * for decor elements such as the status bar. Use the following methods to query the - * application display area: {@link #getSize}, {@link #getRectSize} and {@link #getMetrics}.</li> + * for decor elements such as the status bar. Use {@link WindowMetrics#getSize()} to query the + * application window size.</li> * <li>The real display area specifies the part of the display that contains content * including the system decorations. Even so, the real display area may be smaller than the * physical size of the display if the window manager is emulating a smaller display @@ -97,7 +97,7 @@ public final class Display { // We cache the app width and height properties briefly between calls // to getHeight() and getWidth() to ensure that applications perceive // consistent results when the size changes (most of the time). - // Applications should now be using getSize() instead. + // Applications should now be using WindowMetrics instead. private static final int CACHED_APP_SIZE_DURATION_MILLIS = 20; private long mLastCachedAppSizeUpdate; private int mCachedAppWidthCompat; @@ -674,7 +674,10 @@ public final class Display { * </p> * * @param outSize A {@link Point} object to receive the size information. + * @deprecated Use {@link WindowManager#getCurrentWindowMetrics()} to obtain an instance of + * {@link WindowMetrics} and use {@link WindowMetrics#getSize()} instead. */ + @Deprecated public void getSize(Point outSize) { synchronized (this) { updateDisplayInfoLocked(); @@ -688,8 +691,10 @@ public final class Display { * Gets the size of the display as a rectangle, in pixels. * * @param outSize A {@link Rect} object to receive the size information. - * @see #getSize(Point) + * @deprecated Use {@link WindowMetrics#getSize()} to get the dimensions of the application + * window area. */ + @Deprecated public void getRectSize(Rect outSize) { synchronized (this) { updateDisplayInfoLocked(); @@ -752,7 +757,7 @@ public final class Display { } /** - * @deprecated Use {@link #getSize(Point)} instead. + * @deprecated Use {@link WindowMetrics#getSize()} instead. */ @Deprecated public int getWidth() { @@ -763,7 +768,7 @@ public final class Display { } /** - * @deprecated Use {@link #getSize(Point)} instead. + * @deprecated Use {@link WindowMetrics#getSize()} instead. */ @Deprecated public int getHeight() { @@ -1102,7 +1107,10 @@ public final class Display { * </p> * * @param outMetrics A {@link DisplayMetrics} object to receive the metrics. + * @deprecated Use {@link WindowMetrics#getSize()} to get the dimensions of the application + * window area, and {@link Configuration#densityDpi} to get the current density. */ + @Deprecated public void getMetrics(DisplayMetrics outMetrics) { synchronized (this) { updateDisplayInfoLocked(); diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java index ddfd38c0320b..9901d053184c 100644 --- a/core/java/android/view/InsetsSourceConsumer.java +++ b/core/java/android/view/InsetsSourceConsumer.java @@ -181,8 +181,9 @@ public class InsetsSourceConsumer { } private void applyHiddenToControl() { - if (mSourceControl == null || mSourceControl.getLeash() == null - || mController.getAnimationType(mType) != ANIMATION_TYPE_NONE) { + + // TODO: Handle case properly when animation is running already (it shouldn't!) + if (mSourceControl == null || mSourceControl.getLeash() == null) { return; } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 841c43fb1392..51ea30b41741 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -216,7 +216,7 @@ public final class ViewRootImpl implements ViewParent, * If set to 1, this will switch to a mode where we only use the new approach for IME, but not * for the status/navigation bar. */ - private static final String USE_NEW_INSETS_PROPERTY = "persist.wm.new_insets"; + private static final String USE_NEW_INSETS_PROPERTY = "persist.debug.new_insets"; /** * @see #USE_NEW_INSETS_PROPERTY diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java index c8a7c079994c..78d4e61ea953 100644 --- a/core/java/android/widget/Toast.java +++ b/core/java/android/widget/Toast.java @@ -28,6 +28,7 @@ import android.app.ITransientNotification; import android.app.ITransientNotificationCallback; import android.compat.Compatibility; import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledAfter; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; @@ -112,11 +113,9 @@ public class Toast { /** * Text toasts will be rendered by SystemUI instead of in-app, so apps can't circumvent * background custom toast restrictions. - * - * TODO(b/144152069): Add @EnabledAfter(Q) to target R+ after assessing impact on dogfood */ @ChangeId - // @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q) + @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q) private static final long CHANGE_TEXT_TOASTS_IN_THE_SYSTEM = 147798919L; diff --git a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java index 77d8e0290f20..ab8c19ea8861 100644 --- a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java +++ b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java @@ -18,7 +18,9 @@ package com.android.internal.app; import android.annotation.IntDef; import android.annotation.Nullable; import android.content.Context; +import android.content.pm.ResolveInfo; import android.os.UserHandle; +import android.os.UserManager; import android.view.View; import android.view.ViewGroup; @@ -27,6 +29,7 @@ import com.android.internal.widget.PagerAdapter; import com.android.internal.widget.ViewPager; import java.util.HashSet; +import java.util.List; import java.util.Objects; import java.util.Set; @@ -46,11 +49,17 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter { private int mCurrentPage; private OnProfileSelectedListener mOnProfileSelectedListener; private Set<Integer> mLoadedPages; + private final UserHandle mPersonalProfileUserHandle; + private final UserHandle mWorkProfileUserHandle; - AbstractMultiProfilePagerAdapter(Context context, int currentPage) { + AbstractMultiProfilePagerAdapter(Context context, int currentPage, + UserHandle personalProfileUserHandle, + UserHandle workProfileUserHandle) { mContext = Objects.requireNonNull(context); mCurrentPage = currentPage; mLoadedPages = new HashSet<>(); + mPersonalProfileUserHandle = personalProfileUserHandle; + mWorkProfileUserHandle = workProfileUserHandle; } void setOnProfileSelectedListener(OnProfileSelectedListener listener) { @@ -72,7 +81,7 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter { public void onPageSelected(int position) { mCurrentPage = position; if (!mLoadedPages.contains(position)) { - getActiveListAdapter().rebuildList(); + rebuildActiveTab(true); mLoadedPages.add(position); } if (mOnProfileSelectedListener != null) { @@ -85,6 +94,13 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter { mLoadedPages.add(mCurrentPage); } + void clearInactiveProfileCache() { + if (mLoadedPages.size() == 1) { + return; + } + mLoadedPages.remove(1 - mCurrentPage); + } + @Override public ViewGroup instantiateItem(ViewGroup container, int position) { final ProfileDescriptor profileDescriptor = getItem(position); @@ -187,12 +203,53 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter { @VisibleForTesting public abstract @Nullable ResolverListAdapter getInactiveListAdapter(); + public abstract ResolverListAdapter getPersonalListAdapter(); + + public abstract @Nullable ResolverListAdapter getWorkListAdapter(); + abstract Object getCurrentRootAdapter(); abstract ViewGroup getActiveAdapterView(); abstract @Nullable ViewGroup getInactiveAdapterView(); + boolean rebuildActiveTab(boolean post) { + return rebuildTab(getActiveListAdapter(), post); + } + + boolean rebuildInactiveTab(boolean post) { + if (getItemCount() == 1) { + return false; + } + return rebuildTab(getInactiveListAdapter(), post); + } + + private boolean rebuildTab(ResolverListAdapter activeListAdapter, boolean doPostProcessing) { + UserHandle listUserHandle = activeListAdapter.getUserHandle(); + if (UserHandle.myUserId() != listUserHandle.getIdentifier() && + !hasAppsInOtherProfile(activeListAdapter)) { + // TODO(arangelov): Show empty state UX here + return false; + } else { + return activeListAdapter.rebuildList(doPostProcessing); + } + } + + private boolean hasAppsInOtherProfile(ResolverListAdapter adapter) { + if (mWorkProfileUserHandle == null) { + return false; + } + List<ResolverActivity.ResolvedComponentInfo> resolversForIntent = + adapter.getResolversForUser(UserHandle.of(UserHandle.myUserId())); + for (ResolverActivity.ResolvedComponentInfo info : resolversForIntent) { + ResolveInfo resolveInfo = info.getResolveInfoAt(0); + if (resolveInfo.targetUserId != UserHandle.USER_CURRENT) { + return true; + } + } + return false; + } + protected class ProfileDescriptor { final ViewGroup rootView; ProfileDescriptor(ViewGroup rootView) { diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 65128e4a2eda..a43e4fe118a9 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -53,6 +53,7 @@ import android.content.pm.ResolveInfo; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager; import android.content.res.Configuration; +import android.content.res.Resources; import android.database.Cursor; import android.database.DataSetObserver; import android.graphics.Bitmap; @@ -81,6 +82,7 @@ import android.provider.DeviceConfig; import android.provider.DocumentsContract; import android.provider.Downloads; import android.provider.OpenableColumns; +import android.provider.Settings; import android.service.chooser.ChooserTarget; import android.service.chooser.ChooserTargetService; import android.service.chooser.IChooserTargetResult; @@ -101,6 +103,7 @@ import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; +import android.widget.Button; import android.widget.ImageView; import android.widget.Space; import android.widget.TextView; @@ -131,6 +134,7 @@ import java.io.File; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.net.URISyntaxException; import java.text.Collator; import java.util.ArrayList; import java.util.Collections; @@ -166,6 +170,9 @@ public class ChooserActivity extends ResolverActivity implements private static final String PREF_NUM_SHEET_EXPANSIONS = "pref_num_sheet_expansions"; + private static final String CHIP_LABEL_METADATA_KEY = "android.service.chooser.chip_label"; + private static final String CHIP_ICON_METADATA_KEY = "android.service.chooser.chip_icon"; + private static final boolean DEBUG = true; private static final boolean USE_PREDICTION_MANAGER_FOR_SHARE_ACTIVITIES = true; @@ -527,6 +534,15 @@ public class ChooserActivity extends ResolverActivity implements mIsSuccessfullySelected = false; Intent intent = getIntent(); Parcelable targetParcelable = intent.getParcelableExtra(Intent.EXTRA_INTENT); + if (targetParcelable instanceof Uri) { + try { + targetParcelable = Intent.parseUri(targetParcelable.toString(), + Intent.URI_INTENT_SCHEME); + } catch (URISyntaxException ex) { + // doesn't parse as an intent; let the next test fail and error out + } + } + if (!(targetParcelable instanceof Intent)) { Log.w("ChooserActivity", "Target is not an intent: " + targetParcelable); finish(); @@ -777,7 +793,9 @@ public class ChooserActivity extends ResolverActivity implements /* userHandle */ UserHandle.of(UserHandle.myUserId())); return new ChooserMultiProfilePagerAdapter( /* context */ this, - adapter); + adapter, + getPersonalProfileUserHandle(), + /* workProfileUserHandle= */ null); } private ChooserMultiProfilePagerAdapter createChooserMultiProfilePagerAdapterForTwoProfiles( @@ -804,7 +822,9 @@ public class ChooserActivity extends ResolverActivity implements /* context */ this, personalAdapter, workAdapter, - /* defaultProfile */ getCurrentProfile()); + /* defaultProfile */ getCurrentProfile(), + getPersonalProfileUserHandle(), + getWorkProfileUserHandle()); } @Override @@ -856,11 +876,11 @@ public class ChooserActivity extends ResolverActivity implements } @Override - protected PackageMonitor createPackageMonitor() { + protected PackageMonitor createPackageMonitor(ResolverListAdapter listAdapter) { return new PackageMonitor() { @Override public void onSomePackagesChanged() { - handlePackagesChanged(); + handlePackagesChanged(listAdapter); } }; } @@ -869,9 +889,19 @@ public class ChooserActivity extends ResolverActivity implements * Update UI to reflect changes in data. */ public void handlePackagesChanged() { - // TODO(arangelov): Dispatch this to all adapters when we have the helper methods - // in a follow-up CL - mChooserMultiProfilePagerAdapter.getActiveListAdapter().handlePackagesChanged(); + handlePackagesChanged(/* listAdapter */ null); + } + + /** + * Update UI to reflect changes in data. + * <p>If {@code listAdapter} is {@code null}, both profile list adapters are updated. + */ + private void handlePackagesChanged(@Nullable ResolverListAdapter listAdapter) { + if (listAdapter == null) { + mChooserMultiProfilePagerAdapter.getActiveListAdapter().handlePackagesChanged(); + } else { + listAdapter.handlePackagesChanged(); + } updateProfileViewButton(); } @@ -965,6 +995,108 @@ public class ChooserActivity extends ResolverActivity implements return displayContentPreview(previewType, targetIntent, getLayoutInflater(), parent); } + private ComponentName getNearbySharingComponent() { + String nearbyComponent = Settings.Secure.getString( + getContentResolver(), + Settings.Secure.NEARBY_SHARING_COMPONENT); + if (TextUtils.isEmpty(nearbyComponent)) { + nearbyComponent = getString(R.string.config_defaultNearbySharingComponent); + } + if (TextUtils.isEmpty(nearbyComponent)) { + return null; + } + return ComponentName.unflattenFromString(nearbyComponent); + } + + private TargetInfo getNearbySharingTarget(Intent originalIntent) { + final ComponentName cn = getNearbySharingComponent(); + if (cn == null) return null; + + final Intent resolveIntent = new Intent(); + resolveIntent.setComponent(cn); + final ResolveInfo ri = getPackageManager().resolveActivity( + resolveIntent, PackageManager.GET_META_DATA); + if (ri == null || ri.activityInfo == null) { + Log.e(TAG, "Device-specified nearby sharing component (" + cn + + ") not available"); + return null; + } + + // Allow the nearby sharing component to provide a more appropriate icon and label + // for the chip. + CharSequence name = null; + Drawable icon = null; + final Bundle metaData = ri.activityInfo.metaData; + if (metaData != null) { + try { + final Resources pkgRes = getPackageManager().getResourcesForActivity(cn); + final int nameResId = metaData.getInt(CHIP_LABEL_METADATA_KEY); + name = pkgRes.getString(nameResId); + final int resId = metaData.getInt(CHIP_ICON_METADATA_KEY); + icon = pkgRes.getDrawable(resId); + } catch (Resources.NotFoundException ex) { + } catch (NameNotFoundException ex) { + } + } + if (TextUtils.isEmpty(name)) { + name = ri.loadLabel(getPackageManager()); + } + if (icon == null) { + icon = ri.loadIcon(getPackageManager()); + } + + final DisplayResolveInfo dri = new DisplayResolveInfo( + originalIntent, ri, name, "", resolveIntent, null); + dri.setDisplayIcon(icon); + return dri; + } + + private Button createActionButton(Drawable icon, CharSequence title, View.OnClickListener r) { + Button b = (Button) LayoutInflater.from(this).inflate(R.layout.chooser_action_button, null); + if (icon != null) { + final int size = getResources() + .getDimensionPixelSize(R.dimen.chooser_action_button_icon_size); + icon.setBounds(0, 0, size, size); + b.setCompoundDrawablesRelative(icon, null, null, null); + } + b.setText(title); + b.setOnClickListener(r); + return b; + } + + private Button createCopyButton() { + final Button b = createActionButton( + getDrawable(R.drawable.ic_menu_copy_material), + getString(R.string.copy), this::onCopyButtonClicked); + b.setId(R.id.chooser_copy_button); + return b; + } + + private @Nullable Button createNearbyButton(Intent originalIntent) { + final TargetInfo ti = getNearbySharingTarget(originalIntent); + if (ti == null) return null; + + return createActionButton( + ti.getDisplayIcon(this), + ti.getDisplayLabel(), + (View unused) -> { + safelyStartActivity(ti); + finish(); + } + ); + } + + private void addActionButton(ViewGroup parent, Button b) { + if (b == null) return; + final ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams( + LayoutParams.WRAP_CONTENT, + LayoutParams.WRAP_CONTENT + ); + final int gap = getResources().getDimensionPixelSize(R.dimen.resolver_icon_margin) / 2; + lp.setMarginsRelative(gap, 0, gap, 0); + parent.addView(b, lp); + } + private ViewGroup displayContentPreview(@ContentPreviewType int previewType, Intent targetIntent, LayoutInflater layoutInflater, ViewGroup parent) { ViewGroup layout = null; @@ -995,8 +1127,10 @@ public class ChooserActivity extends ResolverActivity implements ViewGroup contentPreviewLayout = (ViewGroup) layoutInflater.inflate( R.layout.chooser_grid_preview_text, parent, false); - contentPreviewLayout.findViewById(R.id.copy_button).setOnClickListener( - this::onCopyButtonClicked); + final ViewGroup actionRow = + (ViewGroup) contentPreviewLayout.findViewById(R.id.chooser_action_row); + addActionButton(actionRow, createCopyButton()); + addActionButton(actionRow, createNearbyButton(targetIntent)); CharSequence sharingText = targetIntent.getCharSequenceExtra(Intent.EXTRA_TEXT); if (sharingText == null) { @@ -1154,7 +1288,8 @@ public class ChooserActivity extends ResolverActivity implements // TODO(b/120417119): Disable file copy until after moving to sysui, // due to permissions issues - contentPreviewLayout.findViewById(R.id.file_copy_button).setVisibility(View.GONE); + //((ViewGroup) contentPreviewLayout.findViewById(R.id.chooser_action_row)) + // .addView(createCopyButton()); String action = targetIntent.getAction(); if (Intent.ACTION_SEND.equals(action)) { @@ -1680,7 +1815,7 @@ public class ChooserActivity extends ResolverActivity implements } return intentFilter; } catch (Exception e) { - Log.e(TAG, "failed to get target intent filter " + e); + Log.e(TAG, "failed to get target intent filter", e); return null; } } @@ -2337,10 +2472,10 @@ public class ChooserActivity extends ResolverActivity implements } @Override // ResolverListCommunicator - public void onHandlePackagesChanged() { + public void onHandlePackagesChanged(ResolverListAdapter listAdapter) { mServicesRequested.clear(); mChooserMultiProfilePagerAdapter.getActiveListAdapter().notifyDataSetChanged(); - super.onHandlePackagesChanged(); + super.onHandlePackagesChanged(listAdapter); } @Override // SelectableTargetInfoCommunicator diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java index ca3b7e7a7837..74ae29117b59 100644 --- a/core/java/com/android/internal/app/ChooserListAdapter.java +++ b/core/java/com/android/internal/app/ChooserListAdapter.java @@ -19,7 +19,6 @@ package com.android.internal.app; import static com.android.internal.app.ChooserActivity.TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE; import static com.android.internal.app.ChooserActivity.TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER; -import android.annotation.Nullable; import android.app.ActivityManager; import android.app.prediction.AppPredictor; import android.content.ComponentName; @@ -176,7 +175,7 @@ public class ChooserListAdapter extends ResolverListAdapter { Log.d(TAG, "clearing queryTargets on package change"); } createPlaceHolders(); - mChooserListCommunicator.onHandlePackagesChanged(); + mChooserListCommunicator.onHandlePackagesChanged(this); } @@ -541,7 +540,7 @@ public class ChooserListAdapter extends ResolverListAdapter { @Override AsyncTask<List<ResolvedComponentInfo>, Void, - List<ResolvedComponentInfo>> createSortingTask() { + List<ResolvedComponentInfo>> createSortingTask(boolean doPostProcessing) { return new AsyncTask<List<ResolvedComponentInfo>, Void, List<ResolvedComponentInfo>>() { @@ -554,9 +553,11 @@ public class ChooserListAdapter extends ResolverListAdapter { } @Override protected void onPostExecute(List<ResolvedComponentInfo> sortedComponents) { - processSortedList(sortedComponents); - mChooserListCommunicator.updateProfileViewButton(); - notifyDataSetChanged(); + processSortedList(sortedComponents, doPostProcessing); + if (doPostProcessing) { + mChooserListCommunicator.updateProfileViewButton(); + notifyDataSetChanged(); + } } }; } diff --git a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java index 663e0255feb9..e3501422f915 100644 --- a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java +++ b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java @@ -38,8 +38,10 @@ public class ChooserMultiProfilePagerAdapter extends AbstractMultiProfilePagerAd private final ChooserProfileDescriptor[] mItems; ChooserMultiProfilePagerAdapter(Context context, - ChooserActivity.ChooserGridAdapter adapter) { - super(context, /* currentPage */ 0); + ChooserActivity.ChooserGridAdapter adapter, + UserHandle personalProfileUserHandle, + UserHandle workProfileUserHandle) { + super(context, /* currentPage */ 0, personalProfileUserHandle, workProfileUserHandle); mItems = new ChooserProfileDescriptor[] { createProfileDescriptor(adapter) }; @@ -48,8 +50,11 @@ public class ChooserMultiProfilePagerAdapter extends AbstractMultiProfilePagerAd ChooserMultiProfilePagerAdapter(Context context, ChooserActivity.ChooserGridAdapter personalAdapter, ChooserActivity.ChooserGridAdapter workAdapter, - @Profile int defaultProfile) { - super(context, /* currentPage */ defaultProfile); + @Profile int defaultProfile, + UserHandle personalProfileUserHandle, + UserHandle workProfileUserHandle) { + super(context, /* currentPage */ defaultProfile, personalProfileUserHandle, + workProfileUserHandle); mItems = new ChooserProfileDescriptor[] { createProfileDescriptor(personalAdapter), createProfileDescriptor(workAdapter) @@ -131,6 +136,17 @@ public class ChooserMultiProfilePagerAdapter extends AbstractMultiProfilePagerAd } @Override + public ResolverListAdapter getPersonalListAdapter() { + return getAdapterForIndex(PROFILE_PERSONAL).getListAdapter(); + } + + @Override + @Nullable + public ResolverListAdapter getWorkListAdapter() { + return getAdapterForIndex(PROFILE_WORK).getListAdapter(); + } + + @Override ChooserActivity.ChooserGridAdapter getCurrentRootAdapter() { return getAdapterForIndex(getCurrentPage()); } diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index 30a41d338806..051534cc3eb1 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -16,7 +16,9 @@ package com.android.internal.app; +import static android.Manifest.permission.INTERACT_ACROSS_PROFILES; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; +import static android.content.PermissionChecker.PID_UNKNOWN; import static com.android.internal.app.AbstractMultiProfilePagerAdapter.PROFILE_PERSONAL; import static com.android.internal.app.AbstractMultiProfilePagerAdapter.PROFILE_WORK; @@ -36,6 +38,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.PermissionChecker; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; @@ -157,7 +160,8 @@ public class ResolverActivity extends Activity implements private static final String TAB_TAG_PERSONAL = "personal"; private static final String TAB_TAG_WORK = "work"; - private final PackageMonitor mPackageMonitor = createPackageMonitor(); + private PackageMonitor mPersonalPackageMonitor; + private PackageMonitor mWorkPackageMonitor; @VisibleForTesting protected AbstractMultiProfilePagerAdapter mMultiProfilePagerAdapter; @@ -243,11 +247,11 @@ public class ResolverActivity extends Activity implements } } - protected PackageMonitor createPackageMonitor() { + protected PackageMonitor createPackageMonitor(ResolverListAdapter listAdapter) { return new PackageMonitor() { @Override public void onSomePackagesChanged() { - mMultiProfilePagerAdapter.getActiveListAdapter().handlePackagesChanged(); + listAdapter.handlePackagesChanged(); updateProfileViewButton(); } @@ -327,8 +331,6 @@ public class ResolverActivity extends Activity implements mPm = getPackageManager(); - mPackageMonitor.register(this, getMainLooper(), false); - mRegistered = true; mReferrerPackage = getReferrerPackageName(); // Add our initial intent as the first item, regardless of what else has already been added. @@ -353,6 +355,18 @@ public class ResolverActivity extends Activity implements return; } + mPersonalPackageMonitor = createPackageMonitor( + mMultiProfilePagerAdapter.getPersonalListAdapter()); + mPersonalPackageMonitor.register( + this, getMainLooper(), getPersonalProfileUserHandle(), false); + if (hasWorkProfile()) { + mWorkPackageMonitor = createPackageMonitor( + mMultiProfilePagerAdapter.getWorkListAdapter()); + mWorkPackageMonitor.register(this, getMainLooper(), getWorkProfileUserHandle(), false); + } + + mRegistered = true; + final ResolverDrawerLayout rdl = findViewById(R.id.contentPanel); if (rdl != null) { rdl.setOnDismissedListener(new ResolverDrawerLayout.OnDismissedListener() { @@ -419,7 +433,9 @@ public class ResolverActivity extends Activity implements /* userHandle */ UserHandle.of(UserHandle.myUserId())); return new ResolverMultiProfilePagerAdapter( /* context */ this, - adapter); + adapter, + getPersonalProfileUserHandle(), + /* workProfileUserHandle= */ null); } private ResolverMultiProfilePagerAdapter createResolverMultiProfilePagerAdapterForTwoProfiles( @@ -438,20 +454,23 @@ public class ResolverActivity extends Activity implements == getPersonalProfileUserHandle().getIdentifier()), mUseLayoutForBrowsables, /* userHandle */ getPersonalProfileUserHandle()); + UserHandle workProfileUserHandle = getWorkProfileUserHandle(); ResolverListAdapter workAdapter = createResolverListAdapter( /* context */ this, /* payloadIntents */ mIntents, initialIntents, rList, (filterLastUsed && UserHandle.myUserId() - == getWorkProfileUserHandle().getIdentifier()), + == workProfileUserHandle.getIdentifier()), mUseLayoutForBrowsables, - /* userHandle */ getWorkProfileUserHandle()); + /* userHandle */ workProfileUserHandle); return new ResolverMultiProfilePagerAdapter( /* context */ this, personalAdapter, workAdapter, - /* defaultProfile */ getCurrentProfile()); + /* defaultProfile */ getCurrentProfile(), + getPersonalProfileUserHandle(), + getWorkProfileUserHandle()); } protected @Profile int getCurrentProfile() { @@ -543,9 +562,6 @@ public class ResolverActivity extends Activity implements public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); mMultiProfilePagerAdapter.getActiveListAdapter().handlePackagesChanged(); - if (mMultiProfilePagerAdapter.getInactiveListAdapter() != null) { - mMultiProfilePagerAdapter.getInactiveListAdapter().handlePackagesChanged(); - } if (mSystemWindowInsets != null) { mResolverDrawerLayout.setPadding(mSystemWindowInsets.left, mSystemWindowInsets.top, @@ -707,7 +723,16 @@ public class ResolverActivity extends Activity implements protected void onRestart() { super.onRestart(); if (!mRegistered) { - mPackageMonitor.register(this, getMainLooper(), false); + mPersonalPackageMonitor.register(this, getMainLooper(), + getPersonalProfileUserHandle(), false); + if (hasWorkProfile()) { + if (mWorkPackageMonitor == null) { + mWorkPackageMonitor = createPackageMonitor( + mMultiProfilePagerAdapter.getWorkListAdapter()); + } + mWorkPackageMonitor.register(this, getMainLooper(), + getWorkProfileUserHandle(), false); + } mRegistered = true; } mMultiProfilePagerAdapter.getActiveListAdapter().handlePackagesChanged(); @@ -718,7 +743,10 @@ public class ResolverActivity extends Activity implements protected void onStop() { super.onStop(); if (mRegistered) { - mPackageMonitor.unregister(); + mPersonalPackageMonitor.unregister(); + if (mWorkPackageMonitor != null) { + mWorkPackageMonitor.unregister(); + } mRegistered = false; } final Intent intent = getIntent(); @@ -913,26 +941,21 @@ public class ResolverActivity extends Activity implements } @Override // ResolverListCommunicator - public void onPostListReady(ResolverListAdapter listAdapter) { - if (mMultiProfilePagerAdapter.getCurrentUserHandle().getIdentifier() - == UserHandle.myUserId()) { - setHeader(); + public void onPostListReady(ResolverListAdapter listAdapter, boolean doPostProcessing) { + if (isAutolaunching() || maybeAutolaunchActivity()) { + return; } - resetButtonBar(); - onListRebuilt(listAdapter); - } - - protected void onListRebuilt(ResolverListAdapter listAdapter) { - int count = listAdapter.getUnfilteredCount(); - if (count == 1 && listAdapter.getOtherProfile() == null) { - // Only one target, so we're a candidate to auto-launch! - final TargetInfo target = listAdapter.targetInfoForPosition(0, false); - if (shouldAutoLaunchSingleChoice(target)) { - safelyStartActivity(target); - finish(); + if (doPostProcessing) { + if (mMultiProfilePagerAdapter.getCurrentUserHandle().getIdentifier() + == UserHandle.myUserId()) { + setHeader(); } + resetButtonBar(); + onListRebuilt(listAdapter); } + } + protected void onListRebuilt(ResolverListAdapter listAdapter) { final ItemClickListener listener = new ItemClickListener(); setupAdapterListView((ListView) mMultiProfilePagerAdapter.getActiveAdapterView(), listener); } @@ -1132,6 +1155,11 @@ public class ResolverActivity extends Activity implements } private void safelyStartActivityInternal(TargetInfo cti) { + mPersonalPackageMonitor.unregister(); + if (mWorkPackageMonitor != null) { + mWorkPackageMonitor.unregister(); + } + mRegistered = false; // If needed, show that intent is forwarded // from managed profile to owner or other way around. if (mProfileSwitchMessageId != -1) { @@ -1247,7 +1275,11 @@ public class ResolverActivity extends Activity implements throw new IllegalStateException("mMultiProfilePagerAdapter.getCurrentListAdapter() " + "cannot be null."); } - boolean rebuildCompleted = mMultiProfilePagerAdapter.getActiveListAdapter().rebuildList(); + boolean rebuildCompleted = mMultiProfilePagerAdapter.rebuildActiveTab(true); + + // We partially rebuild the inactive adapter to determine if we should auto launch + mMultiProfilePagerAdapter.rebuildInactiveTab(false); + if (useLayoutWithDefault()) { mLayoutId = R.layout.resolver_list_with_default; } else { @@ -1274,25 +1306,12 @@ public class ResolverActivity extends Activity implements * @return <code>true</code> if the activity is finishing and creation should halt. */ final boolean postRebuildListInternal(boolean rebuildCompleted) { - int count = mMultiProfilePagerAdapter.getActiveListAdapter().getUnfilteredCount(); // We only rebuild asynchronously when we have multiple elements to sort. In the case where // we're already done, we can check if we should auto-launch immediately. - if (rebuildCompleted) { - if (count == 1 - && mMultiProfilePagerAdapter.getActiveListAdapter().getOtherProfile() == null) { - // Only one target, so we're a candidate to auto-launch! - final TargetInfo target = mMultiProfilePagerAdapter.getActiveListAdapter() - .targetInfoForPosition(0, false); - if (shouldAutoLaunchSingleChoice(target)) { - safelyStartActivity(target); - mPackageMonitor.unregister(); - mRegistered = false; - finish(); - return true; - } - } + if (rebuildCompleted && maybeAutolaunchActivity()) { + return true; } setupViewVisibilities(); @@ -1304,6 +1323,129 @@ public class ResolverActivity extends Activity implements return false; } + private int isPermissionGranted(String permission, int uid) { + return ActivityManager.checkComponentPermission(permission, uid, + /* owningUid= */-1, /* exported= */ true); + } + + /** + * @return {@code true} if a resolved target is autolaunched, otherwise {@code false} + */ + private boolean maybeAutolaunchActivity() { + int numberOfProfiles = mMultiProfilePagerAdapter.getItemCount(); + if (numberOfProfiles == 1 && maybeAutolaunchIfSingleTarget()) { + return true; + } else if (numberOfProfiles == 2 && maybeAutolaunchIfCrossProfileSupported()) { + // note that autolaunching when we have 2 profiles, 1 resolved target on the active + // tab and 0 resolved targets on the inactive tab, is already handled before launching + // ResolverActivity + return true; + } + return false; + } + + private boolean maybeAutolaunchIfSingleTarget() { + int count = mMultiProfilePagerAdapter.getActiveListAdapter().getUnfilteredCount(); + if (count != 1) { + return false; + } + + // Only one target, so we're a candidate to auto-launch! + final TargetInfo target = mMultiProfilePagerAdapter.getActiveListAdapter() + .targetInfoForPosition(0, false); + if (shouldAutoLaunchSingleChoice(target)) { + safelyStartActivity(target); + finish(); + return true; + } + return false; + } + + /** + * When we have a personal and a work profile, we auto launch in the following scenario: + * - There is 1 resolved target on each profile + * - That target is the same app on both profiles + * - The target app has permission to communicate cross profiles + * - The target app has declared it supports cross-profile communication via manifest metadata + */ + private boolean maybeAutolaunchIfCrossProfileSupported() { + int count = mMultiProfilePagerAdapter.getActiveListAdapter().getUnfilteredCount(); + if (count != 1) { + return false; + } + ResolverListAdapter inactiveListAdapter = + mMultiProfilePagerAdapter.getInactiveListAdapter(); + if (inactiveListAdapter.getUnfilteredCount() != 1) { + return false; + } + TargetInfo activeProfileTarget = mMultiProfilePagerAdapter.getActiveListAdapter() + .targetInfoForPosition(0, false); + TargetInfo inactiveProfileTarget = inactiveListAdapter.targetInfoForPosition(0, false); + if (!Objects.equals(activeProfileTarget.getResolvedComponentName(), + inactiveProfileTarget.getResolvedComponentName())) { + return false; + } + if (!shouldAutoLaunchSingleChoice(activeProfileTarget)) { + return false; + } + String packageName = activeProfileTarget.getResolvedComponentName().getPackageName(); + if (!canAppInteractCrossProfiles(packageName)) { + return false; + } + + safelyStartActivity(activeProfileTarget); + finish(); + return true; + } + + /** + * Returns whether the package has the necessary permissions to interact across profiles on + * behalf of a given user. + * + * <p>This means meeting the following condition: + * <ul> + * <li>The app's {@link ApplicationInfo#crossProfile} flag must be true, and at least + * one of the following conditions must be fulfilled</li> + * <li>{@code Manifest.permission.INTERACT_ACROSS_USERS_FULL} granted.</li> + * <li>{@code Manifest.permission.INTERACT_ACROSS_USERS} granted.</li> + * <li>{@code Manifest.permission.INTERACT_ACROSS_PROFILES} granted, or the corresponding + * AppOps {@code android:interact_across_profiles} is set to "allow".</li> + * </ul> + * + */ + private boolean canAppInteractCrossProfiles(String packageName) { + ApplicationInfo applicationInfo; + try { + applicationInfo = getPackageManager().getApplicationInfo(packageName, 0); + } catch (NameNotFoundException e) { + Log.e(TAG, "Package " + packageName + " does not exist on current user."); + return false; + } + if (!applicationInfo.crossProfile) { + return false; + } + + int packageUid = applicationInfo.uid; + + if (isPermissionGranted(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, + packageUid) == PackageManager.PERMISSION_GRANTED) { + return true; + } + if (isPermissionGranted(android.Manifest.permission.INTERACT_ACROSS_USERS, packageUid) + == PackageManager.PERMISSION_GRANTED) { + return true; + } + if (PermissionChecker.checkPermissionForPreflight(this, INTERACT_ACROSS_PROFILES, + PID_UNKNOWN, packageUid, packageName) == PackageManager.PERMISSION_GRANTED) { + return true; + } + return false; + } + + private boolean isAutolaunching() { + return !mRegistered && isFinishing(); + } + private void setupProfileTabs() { TabHost tabHost = findViewById(R.id.profile_tabhost); tabHost.setup(); @@ -1499,12 +1641,20 @@ public class ResolverActivity extends Activity implements } @Override // ResolverListCommunicator - public void onHandlePackagesChanged() { - ResolverListAdapter activeListAdapter = mMultiProfilePagerAdapter.getActiveListAdapter(); - activeListAdapter.rebuildList(); - if (activeListAdapter.getCount() == 0) { - // We no longer have any items... just finish the activity. - finish(); + public void onHandlePackagesChanged(ResolverListAdapter listAdapter) { + if (listAdapter == mMultiProfilePagerAdapter.getActiveListAdapter()) { + boolean listRebuilt = mMultiProfilePagerAdapter.rebuildActiveTab(true); + if (listRebuilt) { + ResolverListAdapter activeListAdapter = + mMultiProfilePagerAdapter.getActiveListAdapter(); + activeListAdapter.notifyDataSetChanged(); + if (activeListAdapter.getCount() == 0) { + // We no longer have any items... just finish the activity. + finish(); + } + } + } else { + mMultiProfilePagerAdapter.clearInactiveProfileCache(); } } diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java index 405112d99fe7..2321da14cebe 100644 --- a/core/java/com/android/internal/app/ResolverListAdapter.java +++ b/core/java/com/android/internal/app/ResolverListAdapter.java @@ -113,7 +113,7 @@ public class ResolverListAdapter extends BaseAdapter { } public void handlePackagesChanged() { - mResolverListCommunicator.onHandlePackagesChanged(); + mResolverListCommunicator.onHandlePackagesChanged(this); } public void setPlaceholderCount(int count) { @@ -176,9 +176,14 @@ public class ResolverListAdapter extends BaseAdapter { * Rebuild the list of resolvers. In some cases some parts will need some asynchronous work * to complete. * + * The {@code doPostProcessing } parameter is used to specify whether to update the UI and + * load additional targets (e.g. direct share) after the list has been rebuilt. This is used + * in the case where we want to load the inactive profile's resolved apps to know the + * number of targets. + * * @return Whether or not the list building is completed. */ - protected boolean rebuildList() { + protected boolean rebuildList(boolean doPostProcessing) { List<ResolvedComponentInfo> currentResolveList = null; // Clear the value of mOtherProfile from previous call. mOtherProfile = null; @@ -186,6 +191,7 @@ public class ResolverListAdapter extends BaseAdapter { mLastChosenPosition = -1; mAllTargetsAreBrowsers = false; mDisplayList.clear(); + if (mBaseResolveList != null) { currentResolveList = mUnfilteredResolveList = new ArrayList<>(); mResolverListController.addResolveListDedupe(currentResolveList, @@ -198,7 +204,7 @@ public class ResolverListAdapter extends BaseAdapter { mResolverListCommunicator.shouldGetActivityMetadata(), mIntents); if (currentResolveList == null) { - processSortedList(currentResolveList); + processSortedList(currentResolveList, doPostProcessing); return true; } List<ResolvedComponentInfo> originalList = @@ -256,22 +262,22 @@ public class ResolverListAdapter extends BaseAdapter { --placeholderCount; } setPlaceholderCount(placeholderCount); - createSortingTask().execute(currentResolveList); - postListReadyRunnable(); + createSortingTask(doPostProcessing).execute(currentResolveList); + postListReadyRunnable(doPostProcessing); return false; } else { - processSortedList(currentResolveList); + processSortedList(currentResolveList, doPostProcessing); return true; } } else { - processSortedList(currentResolveList); + processSortedList(currentResolveList, doPostProcessing); return true; } } AsyncTask<List<ResolvedComponentInfo>, Void, - List<ResolvedComponentInfo>> createSortingTask() { + List<ResolvedComponentInfo>> createSortingTask(boolean doPostProcessing) { return new AsyncTask<List<ResolvedComponentInfo>, Void, List<ResolvedComponentInfo>>() { @@ -283,15 +289,17 @@ public class ResolverListAdapter extends BaseAdapter { } @Override protected void onPostExecute(List<ResolvedComponentInfo> sortedComponents) { - processSortedList(sortedComponents); - mResolverListCommunicator.updateProfileViewButton(); + processSortedList(sortedComponents, doPostProcessing); notifyDataSetChanged(); + if (doPostProcessing) { + mResolverListCommunicator.updateProfileViewButton(); + } } }; } - - protected void processSortedList(List<ResolvedComponentInfo> sortedComponents) { + protected void processSortedList(List<ResolvedComponentInfo> sortedComponents, + boolean doPostProcessing) { int n; if (sortedComponents != null && (n = sortedComponents.size()) != 0) { mAllTargetsAreBrowsers = mUseLayoutForBrowsables; @@ -343,20 +351,23 @@ public class ResolverListAdapter extends BaseAdapter { } mResolverListCommunicator.sendVoiceChoicesIfNeeded(); - postListReadyRunnable(); + postListReadyRunnable(doPostProcessing); } /** * Some necessary methods for creating the list are initiated in onCreate and will also * determine the layout known. We therefore can't update the UI inline and post to the * handler thread to update after the current task is finished. + * @param doPostProcessing Whether to update the UI and load additional direct share targets + * after the list has been rebuilt */ - void postListReadyRunnable() { + void postListReadyRunnable(boolean doPostProcessing) { if (mPostListReadyRunnable == null) { mPostListReadyRunnable = new Runnable() { @Override public void run() { - mResolverListCommunicator.onPostListReady(ResolverListAdapter.this); + mResolverListCommunicator.onPostListReady(ResolverListAdapter.this, + doPostProcessing); mPostListReadyRunnable = null; } }; @@ -590,6 +601,12 @@ public class ResolverListAdapter extends BaseAdapter { return mResolverListController.getUserHandle(); } + protected List<ResolvedComponentInfo> getResolversForUser(UserHandle userHandle) { + return mResolverListController.getResolversForIntentAsUser(true, + mResolverListCommunicator.shouldGetActivityMetadata(), + mIntents, userHandle); + } + /** * Necessary methods to communicate between {@link ResolverListAdapter} * and {@link ResolverActivity}. @@ -600,7 +617,7 @@ public class ResolverListAdapter extends BaseAdapter { Intent getReplacementIntent(ActivityInfo activityInfo, Intent defIntent); - void onPostListReady(ResolverListAdapter listAdapter); + void onPostListReady(ResolverListAdapter listAdapter, boolean updateUi); void sendVoiceChoicesIfNeeded(); @@ -612,7 +629,7 @@ public class ResolverListAdapter extends BaseAdapter { Intent getTargetIntent(); - void onHandlePackagesChanged(); + void onHandlePackagesChanged(ResolverListAdapter listAdapter); } static class ViewHolder { diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java index 0bfe9eb04d28..022aded188fa 100644 --- a/core/java/com/android/internal/app/ResolverListController.java +++ b/core/java/com/android/internal/app/ResolverListController.java @@ -111,6 +111,15 @@ public class ResolverListController { boolean shouldGetResolvedFilter, boolean shouldGetActivityMetadata, List<Intent> intents) { + return getResolversForIntentAsUser(shouldGetResolvedFilter, shouldGetActivityMetadata, + intents, mUserHandle); + } + + public List<ResolverActivity.ResolvedComponentInfo> getResolversForIntentAsUser( + boolean shouldGetResolvedFilter, + boolean shouldGetActivityMetadata, + List<Intent> intents, + UserHandle userHandle) { List<ResolverActivity.ResolvedComponentInfo> resolvedComponents = null; for (int i = 0, N = intents.size(); i < N; i++) { final Intent intent = intents.get(i); @@ -122,7 +131,7 @@ public class ResolverListController { flags |= PackageManager.MATCH_INSTANT; } final List<ResolveInfo> infos = mpm.queryIntentActivitiesAsUser(intent, flags, - mUserHandle); + userHandle); if (infos != null) { if (resolvedComponents == null) { resolvedComponents = new ArrayList<>(); diff --git a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java index 9d3c6c9ad8b1..96dc83a3f683 100644 --- a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java +++ b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java @@ -36,8 +36,10 @@ public class ResolverMultiProfilePagerAdapter extends AbstractMultiProfilePagerA private final ResolverProfileDescriptor[] mItems; ResolverMultiProfilePagerAdapter(Context context, - ResolverListAdapter adapter) { - super(context, /* currentPage */ 0); + ResolverListAdapter adapter, + UserHandle personalProfileUserHandle, + UserHandle workProfileUserHandle) { + super(context, /* currentPage */ 0, personalProfileUserHandle, workProfileUserHandle); mItems = new ResolverProfileDescriptor[] { createProfileDescriptor(adapter) }; @@ -46,8 +48,11 @@ public class ResolverMultiProfilePagerAdapter extends AbstractMultiProfilePagerA ResolverMultiProfilePagerAdapter(Context context, ResolverListAdapter personalAdapter, ResolverListAdapter workAdapter, - @Profile int defaultProfile) { - super(context, /* currentPage */ defaultProfile); + @Profile int defaultProfile, + UserHandle personalProfileUserHandle, + UserHandle workProfileUserHandle) { + super(context, /* currentPage */ defaultProfile, personalProfileUserHandle, + workProfileUserHandle); mItems = new ResolverProfileDescriptor[] { createProfileDescriptor(personalAdapter), createProfileDescriptor(workAdapter) @@ -116,6 +121,17 @@ public class ResolverMultiProfilePagerAdapter extends AbstractMultiProfilePagerA } @Override + public ResolverListAdapter getPersonalListAdapter() { + return getAdapterForIndex(PROFILE_PERSONAL); + } + + @Override + @Nullable + public ResolverListAdapter getWorkListAdapter() { + return getAdapterForIndex(PROFILE_WORK); + } + + @Override ResolverListAdapter getCurrentRootAdapter() { return getActiveListAdapter(); } diff --git a/core/java/com/android/internal/logging/InstanceId.java b/core/java/com/android/internal/logging/InstanceId.java index 85dbac3f59bb..85643fcffa2f 100644 --- a/core/java/com/android/internal/logging/InstanceId.java +++ b/core/java/com/android/internal/logging/InstanceId.java @@ -16,20 +16,33 @@ package com.android.internal.logging; +import static java.lang.Math.max; +import static java.lang.Math.min; + import android.annotation.Nullable; +import android.os.Parcel; +import android.os.Parcelable; import com.android.internal.annotations.VisibleForTesting; /** * An opaque identifier used to disambiguate which logs refer to a particular instance of some * UI element. Useful when there might be multiple instances simultaneously active. - * Obtain from InstanceIdSequence. + * Obtain from InstanceIdSequence. Clipped to range [0, INSTANCE_ID_MAX]. */ -public class InstanceId { - private int mId; - protected InstanceId(int id) { - mId = id; +public final class InstanceId implements Parcelable { + // At most 20 bits: ~1m possibilities, ~0.5% probability of collision in 100 values + static final int INSTANCE_ID_MAX = 1 << 20; + + private final int mId; + InstanceId(int id) { + mId = min(max(0, id), INSTANCE_ID_MAX); + } + + private InstanceId(Parcel in) { + this(in.readInt()); } + @VisibleForTesting public int getId() { return mId; @@ -47,4 +60,28 @@ public class InstanceId { } return mId == ((InstanceId) obj).mId; } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(mId); + } + + public static final Parcelable.Creator<InstanceId> CREATOR = + new Parcelable.Creator<InstanceId>() { + @Override + public InstanceId createFromParcel(Parcel in) { + return new InstanceId(in); + } + + @Override + public InstanceId[] newArray(int size) { + return new InstanceId[size]; + } + }; + } diff --git a/core/java/com/android/internal/logging/InstanceIdSequence.java b/core/java/com/android/internal/logging/InstanceIdSequence.java index 2e78ed8c5185..aa507e538944 100644 --- a/core/java/com/android/internal/logging/InstanceIdSequence.java +++ b/core/java/com/android/internal/logging/InstanceIdSequence.java @@ -19,6 +19,8 @@ package com.android.internal.logging; import static java.lang.Math.max; import static java.lang.Math.min; +import com.android.internal.annotations.VisibleForTesting; + import java.security.SecureRandom; import java.util.Random; @@ -28,8 +30,6 @@ import java.util.Random; * first use; try to give it a long lifetime. Safe for concurrent use. */ public class InstanceIdSequence { - // At most 20 bits: ~1m possibilities, ~0.5% probability of collision in 100 values - private static final int INSTANCE_ID_MAX = 1 << 20; protected final int mInstanceIdMax; private final Random mRandom = new SecureRandom(); @@ -39,7 +39,7 @@ public class InstanceIdSequence { * an all-zero sequence. */ public InstanceIdSequence(int instanceIdMax) { - mInstanceIdMax = min(max(0, instanceIdMax), INSTANCE_ID_MAX); + mInstanceIdMax = min(max(0, instanceIdMax), InstanceId.INSTANCE_ID_MAX); } /** @@ -47,6 +47,16 @@ public class InstanceIdSequence { * @return new InstanceId */ public InstanceId newInstanceId() { - return new InstanceId(mRandom.nextInt(mInstanceIdMax)); + return newInstanceIdInternal(mRandom.nextInt(mInstanceIdMax)); + } + + /** + * Factory function for instance IDs, used for testing. + * @param id + * @return new InstanceId(id) + */ + @VisibleForTesting + protected InstanceId newInstanceIdInternal(int id) { + return new InstanceId(id); } } diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java index 7adb27cd9e36..db009f68d28a 100644 --- a/core/java/com/android/internal/os/RuntimeInit.java +++ b/core/java/com/android/internal/os/RuntimeInit.java @@ -468,7 +468,8 @@ public class RuntimeInit { try { if (ActivityManager.getService().handleApplicationWtf( mApplicationObject, tag, system, - new ApplicationErrorReport.ParcelableCrashInfo(t))) { + new ApplicationErrorReport.ParcelableCrashInfo(t), + Process.myPid())) { // The Activity Manager has already written us off -- now exit. Process.killProcess(Process.myPid()); System.exit(10); diff --git a/core/res/res/drawable-hdpi/sym_app_on_sd_unavailable_icon.png b/core/res/res/drawable-hdpi/sym_app_on_sd_unavailable_icon.png Binary files differdeleted file mode 100644 index d915d416ff30..000000000000 --- a/core/res/res/drawable-hdpi/sym_app_on_sd_unavailable_icon.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/sym_app_on_sd_unavailable_icon.png b/core/res/res/drawable-ldpi/sym_app_on_sd_unavailable_icon.png Binary files differdeleted file mode 100644 index d88250ae2325..000000000000 --- a/core/res/res/drawable-ldpi/sym_app_on_sd_unavailable_icon.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/sym_app_on_sd_unavailable_icon.png b/core/res/res/drawable-mdpi/sym_app_on_sd_unavailable_icon.png Binary files differdeleted file mode 100644 index 47306683f374..000000000000 --- a/core/res/res/drawable-mdpi/sym_app_on_sd_unavailable_icon.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/sym_app_on_sd_unavailable_icon.png b/core/res/res/drawable-xhdpi/sym_app_on_sd_unavailable_icon.png Binary files differdeleted file mode 100644 index e4e6a5a70df2..000000000000 --- a/core/res/res/drawable-xhdpi/sym_app_on_sd_unavailable_icon.png +++ /dev/null diff --git a/core/res/res/drawable/chooser_action_button_bg.xml b/core/res/res/drawable/chooser_action_button_bg.xml new file mode 100644 index 000000000000..a434c0b9b6a9 --- /dev/null +++ b/core/res/res/drawable/chooser_action_button_bg.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2019 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> +<ripple xmlns:android="http://schemas.android.com/apk/res/android" + android:color="@color/lighter_gray"> + <item> + <inset + android:insetLeft="0dp" + android:insetTop="8dp" + android:insetRight="0dp" + android:insetBottom="8dp"> + <shape android:shape="rectangle"> + <corners android:radius="16dp"></corners> + <stroke android:width="1dp" + android:color="?attr/textColorSecondary" /> + <solid android:color="?attr/colorBackground" /> + </shape> + </inset> + </item> +</ripple> diff --git a/core/res/res/drawable/ic_content_copy_gm2.xml b/core/res/res/drawable/ic_content_copy_gm2.xml deleted file mode 100644 index ee58738b75d0..000000000000 --- a/core/res/res/drawable/ic_content_copy_gm2.xml +++ /dev/null @@ -1,25 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2019 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24" - android:viewportHeight="24"> - <path - android:fillColor="?android:attr/textColorSecondary" - android:pathData="M18,21L4,21L4,7L2,7v14c0,1.1 0.9,2 2,2h14v-2zM21,17L21,3c0,-1.1 -0.9,-2 -2,-2L8,1c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2zM19,17L8,17L8,3h11v14z"/> -</vector> diff --git a/core/res/res/drawable/ic_menu_copy_material.xml b/core/res/res/drawable/ic_menu_copy_material.xml index c03723b1fb33..8c9f1c514b97 100644 --- a/core/res/res/drawable/ic_menu_copy_material.xml +++ b/core/res/res/drawable/ic_menu_copy_material.xml @@ -1,26 +1,27 @@ -<!-- -Copyright (C) 2014 The Android Open Source Project +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 The Android Open Source Project - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at + 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 + http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. --> + <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24.0" - android:viewportHeight="24.0" - android:autoMirrored="true" - android:tint="?attr/colorControlNormal"> - <path - android:pathData="M16,1L4,1C2.9,1 2,1.9 2,3l0,14l2,0L4,3l12,0L16,1zM19,5L8,5C6.9,5 6,5.9 6,7l0,14c0,1.1 0.9,2 2,2l11,0c1.1,0 2,-0.9 2,-2L21,7C21,5.9 20.1,5 19,5zM19,21L8,21L8,7l11,0L19,21z" - android:fillColor="@color/white"/> + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24" + android:autoMirrored="true" + android:tint="?attr/colorControlNormal"> + <path + android:fillColor="@color/white" + android:pathData="M18,21L4,21L4,7L2,7v14c0,1.1 0.9,2 2,2h14v-2zM21,17L21,3c0,-1.1 -0.9,-2 -2,-2L8,1c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2zM19,17L8,17L8,3h11v14z"/> </vector> diff --git a/core/res/res/drawable/sym_app_on_sd_unavailable_icon.xml b/core/res/res/drawable/sym_app_on_sd_unavailable_icon.xml new file mode 100644 index 000000000000..50f15cab1814 --- /dev/null +++ b/core/res/res/drawable/sym_app_on_sd_unavailable_icon.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> + <background android:drawable="@drawable/sym_def_app_icon_background" /> + <foreground > + <vector + android:height="108dp" + android:width="108dp" + android:viewportHeight="108.0" + android:viewportWidth="108.0"> + <path android:fillColor="#202124" android:pathData=" +M68,54h-7.25L54,60.75V76c0,2.2,1.8,4,4,4h10c2.2,0,4-1.8,4-4V58C72,55.8,70.2,54,68,54z"/> + + <path android:fillColor="#FFFFFF" android:pathData=" +M64.59,34.48l3.9-3.9c0.6-0.6,0.6-1.53,0-2.13c-0.6-0.6-1.53-0.6-2.13,0l-4.44,4.44 +C59.55,31.69,56.85,31,54,31c-2.88,0-5.58,0.69-7.98,1.89l-4.47-4.44c-0.6-0.6-1.53-0.6-2.13,0c-0.6,0.6-0.6,1.53,0,2.13l3.93,3.93 +C38.91,37.78,36,43.03,36,49h36C72,43.03,69.09,37.75,64.59,34.48z M48,43h-3v-3h3V43z M63,43h-3v-3h3V43z + +M52,76.01C52,76,52,76,52,76.01l0-15.26v-0.83l0,0v-0.01h0.01l0.58-0.58l6.75-6.75L59.92,52v0H40 +c-2.21,0-4,1.79-4,4v20c0,2.21,1.79,4,4,4h12V76.01z + +M66.84,68.75h-2.81v6.75h2.81c0.93,0,1.69-0.75,1.69-1.69v-3.38C68.52,69.5,67.77,68.75,66.84,68.75z +M66.84,73.81h-1.12v-3.38h1.12V73.81z + +M63.02,70.16h-3.09v1.27h1.97c0.62,0,1.12,0.64,1.12,1.26v1.69c0,0.62-0.51,1.12-1.12,1.12h-3.38v-1.41 +h3.09v-1.27h-1.96c-0.62,0-1.12-0.64-1.12-1.26v-1.69c0-0.62,0.51-1.12,1.12-1.12h3.36V70.16z"/> + + <path android:fillColor="#FFE082" android:pathData=" +M 59 58.5 h 2.5 v 4.5 h -2.5z +M 62.5 58.5 h 2.5 v 4.5 h -2.5z +M 66 58.5 h 2.5 v 4.5 h -2.5z"/> + </vector> + </foreground> +</adaptive-icon> diff --git a/core/res/res/layout/chooser_action_button.xml b/core/res/res/layout/chooser_action_button.xml new file mode 100644 index 000000000000..119b2e90292d --- /dev/null +++ b/core/res/res/layout/chooser_action_button.xml @@ -0,0 +1,30 @@ +<!-- + ~ Copyright (C) 2019 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> + +<Button xmlns:android="http://schemas.android.com/apk/res/android" + android:gravity="center_vertical|start" + android:paddingStart="12dp" + android:paddingEnd="12dp" + android:drawablePadding="8dp" + android:textColor="?android:textColorSecondary" + android:textSize="12sp" + android:maxWidth="192dp" + android:singleLine="true" + android:clickable="true" + android:background="@drawable/chooser_action_button_bg" + android:drawableTint="?android:attr/colorControlNormal" + android:drawableTintMode="src_in" + /> diff --git a/core/res/res/layout/chooser_action_row.xml b/core/res/res/layout/chooser_action_row.xml new file mode 100644 index 000000000000..ea7561124181 --- /dev/null +++ b/core/res/res/layout/chooser_action_row.xml @@ -0,0 +1,26 @@ +<!-- + ~ Copyright (C) 2019 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingLeft="@dimen/chooser_edge_margin_normal" + android:paddingRight="@dimen/chooser_edge_margin_normal" + android:gravity="center" + > + +</LinearLayout> diff --git a/core/res/res/layout/chooser_grid_preview_file.xml b/core/res/res/layout/chooser_grid_preview_file.xml index f7d60c91052d..2a39215a4bd8 100644 --- a/core/res/res/layout/chooser_grid_preview_file.xml +++ b/core/res/res/layout/chooser_grid_preview_file.xml @@ -65,13 +65,15 @@ android:gravity="start|top" android:paddingRight="24dp" android:singleLine="true"/> - <Button - android:id="@+id/file_copy_button" - android:layout_width="24dp" - android:layout_height="24dp" - android:gravity="center" - android:layout_gravity="center_vertical" - android:background="@drawable/ic_content_copy_gm2"/> </LinearLayout> + + <include + android:id="@+id/chooser_action_row" + layout="@layout/chooser_action_row" + android:layout_width="@dimen/chooser_preview_width" + android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/chooser_view_spacing" + android:layout_gravity="center" + /> </LinearLayout> diff --git a/core/res/res/layout/chooser_grid_preview_image.xml b/core/res/res/layout/chooser_grid_preview_image.xml index 79a0de4b271f..62df1650612a 100644 --- a/core/res/res/layout/chooser_grid_preview_image.xml +++ b/core/res/res/layout/chooser_grid_preview_image.xml @@ -78,5 +78,15 @@ android:scaleType="centerCrop"/> </RelativeLayout> + + <include + android:id="@+id/chooser_action_row" + layout="@layout/chooser_action_row" + android:layout_width="@dimen/chooser_preview_width" + android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/chooser_view_spacing" + android:layout_gravity="center" + /> + </LinearLayout> diff --git a/core/res/res/layout/chooser_grid_preview_text.xml b/core/res/res/layout/chooser_grid_preview_text.xml index 4d7846dfb9cc..002917463ab3 100644 --- a/core/res/res/layout/chooser_grid_preview_text.xml +++ b/core/res/res/layout/chooser_grid_preview_text.xml @@ -37,10 +37,9 @@ <TextView android:id="@+id/content_preview_text" - android:layout_width="wrap_content" + android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentStart="true" - android:layout_toStartOf="@id/copy_button" android:layout_centerVertical="true" android:ellipsize="end" android:fontFamily="@android:string/config_headlineFontFamily" @@ -48,40 +47,17 @@ android:maxLines="2" android:focusable="true"/> - <LinearLayout - android:id="@+id/copy_button" - android:orientation="vertical" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_centerVertical="true" - android:layout_alignParentEnd="true" - android:layout_marginStart="@dimen/chooser_view_spacing" - android:gravity="center" - android:minWidth="48dp" - android:minHeight="48dp" - android:clickable="true" - style="?attr/borderlessButtonStyle"> - - <ImageView - android:layout_width="24dp" - android:layout_height="24dp" - android:gravity="top|center_horizontal" - android:src="@drawable/ic_content_copy_gm2" /> - - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="4dp" - android:gravity="center_horizontal" - android:text="@string/copy" - android:textColor="?android:textColorSecondary" - android:textSize="12sp" - android:maxWidth="72dp" - android:maxLines="2" - android:ellipsize="end" /> - </LinearLayout> </RelativeLayout> + <include + android:id="@+id/chooser_action_row" + layout="@layout/chooser_action_row" + android:layout_width="@dimen/chooser_preview_width" + android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/chooser_view_spacing" + android:layout_gravity="center" + /> + <!-- Required sub-layout so we can get the nice rounded corners--> <!-- around this section --> <LinearLayout diff --git a/core/res/res/mipmap-hdpi/sym_app_on_sd_unavailable_icon.png b/core/res/res/mipmap-hdpi/sym_app_on_sd_unavailable_icon.png Binary files differdeleted file mode 100644 index d915d416ff30..000000000000 --- a/core/res/res/mipmap-hdpi/sym_app_on_sd_unavailable_icon.png +++ /dev/null diff --git a/core/res/res/mipmap-ldpi/sym_app_on_sd_unavailable_icon.png b/core/res/res/mipmap-ldpi/sym_app_on_sd_unavailable_icon.png Binary files differdeleted file mode 100644 index d88250ae2325..000000000000 --- a/core/res/res/mipmap-ldpi/sym_app_on_sd_unavailable_icon.png +++ /dev/null diff --git a/core/res/res/mipmap-mdpi/sym_app_on_sd_unavailable_icon.png b/core/res/res/mipmap-mdpi/sym_app_on_sd_unavailable_icon.png Binary files differdeleted file mode 100644 index 47306683f374..000000000000 --- a/core/res/res/mipmap-mdpi/sym_app_on_sd_unavailable_icon.png +++ /dev/null diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index e98f8ba3cda7..52b92d2660da 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -4323,4 +4323,12 @@ <item>4</item> <!-- PROCESS_STATE_FOREGROUND_SERVICE --> <item>12</item> <!-- PROCESS_STATE_TOP_SLEEPING --> </integer-array> + + <!-- Component name that accepts ACTION_SEND intents for nearby (proximity-based) sharing. + Used by ChooserActivity. --> + <string translatable="false" name="config_defaultNearbySharingComponent"></string> + + <!-- Boolean indicating whether frameworks needs to reset cell broadcast geo-fencing + check after reboot or airplane mode toggling --> + <bool translatable="false" name="reset_geo_fencing_check_after_boot_or_apm">false</bool> </resources> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index d437aa1c340c..0b5082cdaf94 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -774,6 +774,8 @@ <dimen name="resolver_edge_margin">24dp</dimen> <dimen name="resolver_elevation">1dp</dimen> + <dimen name="chooser_action_button_icon_size">18dp</dimen> + <!-- Assistant handles --> <dimen name="assist_handle_shadow_radius">2dp</dimen> diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml index ddd9ba43fe09..51ed08b88111 100644 --- a/core/res/res/values/ids.xml +++ b/core/res/res/values/ids.xml @@ -194,6 +194,9 @@ <!-- A tag used to save the index where the custom view is stored --> <item type="id" name="notification_custom_view_index_tag" /> + <!-- Marks the "copy to clipboard" button in the ChooserActivity --> + <item type="id" name="chooser_copy_button" /> + <!-- Accessibility action identifier for {@link android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_BACK}. --> <item type="id" name="accessibilitySystemActionBack" /> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index e4717f817688..21128e33b6e5 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -66,8 +66,7 @@ <java-symbol type="id" name="content_preview_text_layout" /> <java-symbol type="id" name="content_preview_title" /> <java-symbol type="id" name="content_preview_title_layout" /> - <java-symbol type="id" name="copy_button" /> - <java-symbol type="id" name="file_copy_button" /> + <java-symbol type="id" name="chooser_action_row" /> <java-symbol type="id" name="current_scene" /> <java-symbol type="id" name="scene_layoutid_cache" /> <java-symbol type="id" name="customPanel" /> @@ -3783,6 +3782,11 @@ <java-symbol type="string" name="config_factoryResetPackage" /> <java-symbol type="array" name="config_highRefreshRateBlacklist" /> + <java-symbol type="id" name="chooser_copy_button" /> + <java-symbol type="layout" name="chooser_action_button" /> + <java-symbol type="dimen" name="chooser_action_button_icon_size" /> + <java-symbol type="string" name="config_defaultNearbySharingComponent" /> + <java-symbol type="bool" name="config_automotiveHideNavBarForKeyboard" /> <java-symbol type="bool" name="config_showBuiltinWirelessChargingAnim" /> 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 d4c362143bf0..df6b9066ea5c 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java +++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java @@ -64,7 +64,6 @@ import android.graphics.Paint; import android.graphics.drawable.Icon; import android.metrics.LogMaker; import android.net.Uri; -import android.os.Bundle; import android.os.UserHandle; import android.service.chooser.ChooserTarget; @@ -77,9 +76,6 @@ import com.android.internal.app.chooser.DisplayResolveInfo; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import org.hamcrest.BaseMatcher; -import org.hamcrest.Description; -import org.hamcrest.Matcher; import org.junit.Before; import org.junit.Ignore; import org.junit.Rule; @@ -482,8 +478,8 @@ public class ChooserActivityTest { .launchActivity(Intent.createChooser(sendIntent, null)); waitForIdle(); - onView(withId(R.id.copy_button)).check(matches(isDisplayed())); - onView(withId(R.id.copy_button)).perform(click()); + onView(withId(R.id.chooser_copy_button)).check(matches(isDisplayed())); + onView(withId(R.id.chooser_copy_button)).perform(click()); ClipboardManager clipboard = (ClipboardManager) activity.getSystemService( Context.CLIPBOARD_SERVICE); ClipData clipData = clipboard.getPrimaryClip(); @@ -510,8 +506,8 @@ public class ChooserActivityTest { .launchActivity(Intent.createChooser(sendIntent, null)); waitForIdle(); - onView(withId(R.id.copy_button)).check(matches(isDisplayed())); - onView(withId(R.id.copy_button)).perform(click()); + onView(withId(R.id.chooser_copy_button)).check(matches(isDisplayed())); + onView(withId(R.id.chooser_copy_button)).perform(click()); verify(mockLogger, atLeastOnce()).write(logMakerCaptor.capture()); // First is Activity shown, Second is "with preview" diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java index 42f7736d37b0..911490f30799 100644 --- a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java +++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java @@ -27,12 +27,14 @@ import static androidx.test.espresso.matcher.ViewMatchers.withText; import static com.android.internal.app.MatcherUtils.first; import static com.android.internal.app.ResolverDataProvider.createPackageManagerMockedInfo; +import static com.android.internal.app.ResolverDataProvider.createResolvedComponentInfoWithOtherId; import static com.android.internal.app.ResolverWrapperActivity.sOverrides; import static org.hamcrest.CoreMatchers.allOf; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.MatcherAssert.assertThat; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; import android.content.Intent; @@ -465,14 +467,33 @@ public class ResolverActivityTest { // enable the work tab feature flag ResolverActivity.ENABLE_TABBED_VIEW = true; List<ResolvedComponentInfo> personalResolvedComponentInfos = - createResolvedComponentsForTest(3); + createResolvedComponentsForTestWithOtherProfile(3); List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4); - when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(), + when(sOverrides.resolverListController.getResolversForIntentAsUser( Mockito.anyBoolean(), - Mockito.isA(List.class))).thenReturn(personalResolvedComponentInfos); + Mockito.anyBoolean(), + Mockito.isA(List.class), + eq(UserHandle.SYSTEM))).thenReturn(new ArrayList<>(personalResolvedComponentInfos)); + when(sOverrides.resolverListController.getResolversForIntentAsUser( + Mockito.anyBoolean(), + Mockito.anyBoolean(), + Mockito.isA(List.class), + eq(sOverrides.workProfileUserHandle))).thenReturn(new ArrayList<>(workResolvedComponentInfos)); + when(sOverrides.workResolverListController.getResolversForIntentAsUser(Mockito.anyBoolean(), + Mockito.anyBoolean(), + Mockito.isA(List.class), + eq(sOverrides.workProfileUserHandle))).thenReturn(new ArrayList<>(workResolvedComponentInfos)); when(sOverrides.workResolverListController.getResolversForIntent(Mockito.anyBoolean(), Mockito.anyBoolean(), - Mockito.isA(List.class))).thenReturn(workResolvedComponentInfos); + Mockito.isA(List.class))).thenReturn(new ArrayList<>(workResolvedComponentInfos)); + when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(), + Mockito.anyBoolean(), + Mockito.isA(List.class))).thenReturn(new ArrayList<>(personalResolvedComponentInfos)); + when(sOverrides.workResolverListController.getResolversForIntentAsUser(Mockito.anyBoolean(), + Mockito.anyBoolean(), + Mockito.isA(List.class), + eq(UserHandle.SYSTEM))).thenReturn(new ArrayList<>(personalResolvedComponentInfos)); + Intent sendIntent = createSendImageIntent(); markWorkProfileUserAvailable(); @@ -502,9 +523,9 @@ public class ResolverActivityTest { final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent); waitForIdle(); + onView(withText(R.string.resolver_work_tab)) .perform(click()); - waitForIdle(); assertThat(activity.getWorkListAdapter().getCount(), is(4)); } @@ -553,10 +574,35 @@ public class ResolverActivityTest { // enable the work tab feature flag ResolverActivity.ENABLE_TABBED_VIEW = true; markWorkProfileUserAvailable(); + List<ResolvedComponentInfo> personalResolvedComponentInfos = + createResolvedComponentsForTestWithOtherProfile(1); List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4); + + when(sOverrides.resolverListController.getResolversForIntentAsUser( + Mockito.anyBoolean(), + Mockito.anyBoolean(), + Mockito.isA(List.class), + eq(UserHandle.SYSTEM))).thenReturn(new ArrayList<>(personalResolvedComponentInfos)); + when(sOverrides.resolverListController.getResolversForIntentAsUser( + Mockito.anyBoolean(), + Mockito.anyBoolean(), + Mockito.isA(List.class), + eq(sOverrides.workProfileUserHandle))).thenReturn(new ArrayList<>(workResolvedComponentInfos)); + when(sOverrides.workResolverListController.getResolversForIntentAsUser(Mockito.anyBoolean(), + Mockito.anyBoolean(), + Mockito.isA(List.class), + eq(sOverrides.workProfileUserHandle))).thenReturn(new ArrayList<>(workResolvedComponentInfos)); when(sOverrides.workResolverListController.getResolversForIntent(Mockito.anyBoolean(), Mockito.anyBoolean(), - Mockito.isA(List.class))).thenReturn(workResolvedComponentInfos); + Mockito.isA(List.class))).thenReturn(new ArrayList<>(workResolvedComponentInfos)); + when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(), + Mockito.anyBoolean(), + Mockito.isA(List.class))).thenReturn(new ArrayList<>(personalResolvedComponentInfos)); + when(sOverrides.workResolverListController.getResolversForIntentAsUser(Mockito.anyBoolean(), + Mockito.anyBoolean(), + Mockito.isA(List.class), + eq(UserHandle.SYSTEM))).thenReturn(new ArrayList<>(personalResolvedComponentInfos)); + Intent sendIntent = createSendImageIntent(); final ResolverWrapperActivity activity = mActivityRule.launchActivity(sendIntent); diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 79589bf13853..91c5fbec888a 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -331,6 +331,12 @@ "group": "WM_DEBUG_RECENTS_ANIMATIONS", "at": "com\/android\/server\/wm\/RecentsAnimation.java" }, + "-1410260105": { + "message": "Schedule IME show for %s", + "level": "DEBUG", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" + }, "-1391944764": { "message": "SURFACE DESTROY: %s. %s", "level": "INFO", @@ -733,12 +739,6 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/DisplayRotation.java" }, - "-554834595": { - "message": "Display id=%d is frozen, return %d", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, "-549028919": { "message": "enableScreenIfNeededLocked: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s", "level": "INFO", @@ -1063,6 +1063,12 @@ "group": "WM_SHOW_TRANSACTIONS", "at": "com\/android\/server\/wm\/WindowSurfaceController.java" }, + "140319294": { + "message": "IME target changed within ActivityRecord", + "level": "DEBUG", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" + }, "146871307": { "message": "Tried to remove starting window but startingWindow was null: %s", "level": "VERBOSE", @@ -1267,6 +1273,12 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "438102669": { + "message": "call showInsets(ime) on %s", + "level": "DEBUG", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" + }, "457951957": { "message": "\tNot visible=%s", "level": "DEBUG", @@ -1387,6 +1399,12 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "632168013": { + "message": "dcTarget: %s mImeTargetFromIme: %s", + "level": "DEBUG", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" + }, "633654009": { "message": "SURFACE POS (setPositionInTransaction) @ (%f,%f): %s", "level": "INFO", @@ -1693,6 +1711,12 @@ "group": "WM_DEBUG_ADD_REMOVE", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, + "1373000889": { + "message": "abortShowImePostLayout", + "level": "DEBUG", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" + }, "1401700824": { "message": "Window drawn win=%s", "level": "DEBUG", @@ -1987,6 +2011,12 @@ "group": "WM_DEBUG_ADD_REMOVE", "at": "com\/android\/server\/wm\/WindowState.java" }, + "1928325128": { + "message": "Run showImeRunner", + "level": "DEBUG", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" + }, "1947239194": { "message": "Deferring rotation, still finishing previous rotation", "level": "VERBOSE", @@ -2139,6 +2169,9 @@ "WM_DEBUG_FOCUS_LIGHT": { "tag": "WindowManager" }, + "WM_DEBUG_IME": { + "tag": "WindowManager" + }, "WM_DEBUG_KEEP_SCREEN_ON": { "tag": "WindowManager" }, diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp index 7c0efe16838e..58cc08bc2d73 100644 --- a/libs/hwui/hwui/Bitmap.cpp +++ b/libs/hwui/hwui/Bitmap.cpp @@ -479,6 +479,14 @@ bool Bitmap::compress(JavaCompressFormat format, int32_t quality, SkWStream* str bool Bitmap::compress(const SkBitmap& bitmap, JavaCompressFormat format, int32_t quality, SkWStream* stream) { + if (bitmap.colorType() == kAlpha_8_SkColorType) { + // None of the JavaCompressFormats have a sensible way to compress an + // ALPHA_8 Bitmap. SkPngEncoder will compress one, but it uses a non- + // standard format that most decoders do not understand, so this is + // likely not useful. + return false; + } + SkEncodedImageFormat fm; switch (format) { case JavaCompressFormat::Jpeg: diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRoute2InfoTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRoute2InfoTest.java deleted file mode 100644 index c46966fdc6d8..000000000000 --- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRoute2InfoTest.java +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Copyright 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.mediaroutertest; - - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.testng.Assert.assertThrows; - -import android.media.MediaRoute2Info; -import android.net.Uri; -import android.os.Bundle; -import android.os.Parcel; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.ArrayList; -import java.util.List; - -/** - * Tests {@link MediaRoute2Info} and its {@link MediaRoute2Info.Builder builder}. - */ -@RunWith(AndroidJUnit4.class) -@SmallTest -public class MediaRoute2InfoTest { - - public static final String TEST_ID = "test_id"; - public static final String TEST_NAME = "test_name"; - public static final String TEST_ROUTE_TYPE_0 = "test_route_type_0"; - public static final String TEST_ROUTE_TYPE_1 = "test_route_type_1"; - public static final int TEST_DEVICE_TYPE = MediaRoute2Info.DEVICE_TYPE_REMOTE_SPEAKER; - public static final Uri TEST_ICON_URI = Uri.parse("https://developer.android.com"); - public static final String TEST_DESCRIPTION = "test_description"; - public static final int TEST_CONNECTION_STATE = MediaRoute2Info.CONNECTION_STATE_CONNECTING; - public static final String TEST_CLIENT_PACKAGE_NAME = "com.test.client.package.name"; - public static final int TEST_VOLUME_HANDLING = MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE; - public static final int TEST_VOLUME_MAX = 100; - public static final int TEST_VOLUME = 65; - - public static final String TEST_KEY = "test_key"; - public static final String TEST_VALUE = "test_value"; - - @Test - public void testBuilderConstructorWithInvalidValues() { - final String nullId = null; - final String nullName = null; - final String emptyId = ""; - final String emptyName = ""; - final String validId = "valid_id"; - final String validName = "valid_name"; - - // ID is invalid - assertThrows(IllegalArgumentException.class, - () -> new MediaRoute2Info.Builder(nullId, validName)); - assertThrows(IllegalArgumentException.class, - () -> new MediaRoute2Info.Builder(emptyId, validName)); - - // name is invalid - assertThrows(IllegalArgumentException.class, - () -> new MediaRoute2Info.Builder(validId, nullName)); - assertThrows(IllegalArgumentException.class, - () -> new MediaRoute2Info.Builder(validId, emptyName)); - - // Both are invalid - assertThrows(IllegalArgumentException.class, - () -> new MediaRoute2Info.Builder(nullId, nullName)); - assertThrows(IllegalArgumentException.class, - () -> new MediaRoute2Info.Builder(nullId, emptyName)); - assertThrows(IllegalArgumentException.class, - () -> new MediaRoute2Info.Builder(emptyId, nullName)); - assertThrows(IllegalArgumentException.class, - () -> new MediaRoute2Info.Builder(emptyId, emptyName)); - - - // Null RouteInfo (1-argument constructor) - final MediaRoute2Info nullRouteInfo = null; - assertThrows(NullPointerException.class, - () -> new MediaRoute2Info.Builder(nullRouteInfo)); - } - - @Test - public void testBuilderBuildWithEmptyRouteTypesShouldThrowIAE() { - MediaRoute2Info.Builder builder = new MediaRoute2Info.Builder(TEST_ID, TEST_NAME); - assertThrows(IllegalArgumentException.class, () -> builder.build()); - } - - @Test - public void testBuilderAndGettersOfMediaRoute2Info() { - Bundle extras = new Bundle(); - extras.putString(TEST_KEY, TEST_VALUE); - - MediaRoute2Info routeInfo = new MediaRoute2Info.Builder(TEST_ID, TEST_NAME) - .addFeature(TEST_ROUTE_TYPE_0) - .addFeature(TEST_ROUTE_TYPE_1) - .setDeviceType(TEST_DEVICE_TYPE) - .setIconUri(TEST_ICON_URI) - .setDescription(TEST_DESCRIPTION) - .setConnectionState(TEST_CONNECTION_STATE) - .setClientPackageName(TEST_CLIENT_PACKAGE_NAME) - .setVolumeHandling(TEST_VOLUME_HANDLING) - .setVolumeMax(TEST_VOLUME_MAX) - .setVolume(TEST_VOLUME) - .setExtras(extras) - .build(); - - assertEquals(TEST_ID, routeInfo.getId()); - assertEquals(TEST_NAME, routeInfo.getName()); - - assertEquals(2, routeInfo.getFeatures().size()); - assertEquals(TEST_ROUTE_TYPE_0, routeInfo.getFeatures().get(0)); - assertEquals(TEST_ROUTE_TYPE_1, routeInfo.getFeatures().get(1)); - - assertEquals(TEST_DEVICE_TYPE, routeInfo.getDeviceType()); - assertEquals(TEST_ICON_URI, routeInfo.getIconUri()); - assertEquals(TEST_DESCRIPTION, routeInfo.getDescription()); - assertEquals(TEST_CONNECTION_STATE, routeInfo.getConnectionState()); - assertEquals(TEST_CLIENT_PACKAGE_NAME, routeInfo.getClientPackageName()); - assertEquals(TEST_VOLUME_HANDLING, routeInfo.getVolumeHandling()); - assertEquals(TEST_VOLUME_MAX, routeInfo.getVolumeMax()); - assertEquals(TEST_VOLUME, routeInfo.getVolume()); - - Bundle extrasOut = routeInfo.getExtras(); - assertNotNull(extrasOut); - assertTrue(extrasOut.containsKey(TEST_KEY)); - assertEquals(TEST_VALUE, extrasOut.getString(TEST_KEY)); - } - - @Test - public void testBuilderSetExtrasWithNull() { - MediaRoute2Info routeInfo = new MediaRoute2Info.Builder(TEST_ID, TEST_NAME) - .addFeature(TEST_ROUTE_TYPE_0) - .setExtras(null) - .build(); - - assertNull(routeInfo.getExtras()); - } - - @Test - public void testBuilderaddFeatures() { - List<String> routeTypes = new ArrayList<>(); - routeTypes.add(TEST_ROUTE_TYPE_0); - routeTypes.add(TEST_ROUTE_TYPE_1); - - MediaRoute2Info routeInfo = new MediaRoute2Info.Builder(TEST_ID, TEST_NAME) - .addFeatures(routeTypes) - .build(); - - assertEquals(routeTypes, routeInfo.getFeatures()); - } - - @Test - public void testBuilderclearFeatures() { - MediaRoute2Info routeInfo = new MediaRoute2Info.Builder(TEST_ID, TEST_NAME) - .addFeature(TEST_ROUTE_TYPE_0) - .addFeature(TEST_ROUTE_TYPE_1) - // clearFeatures should clear the route types. - .clearFeatures() - .addFeature(TEST_ROUTE_TYPE_1) - .build(); - - assertEquals(1, routeInfo.getFeatures().size()); - assertEquals(TEST_ROUTE_TYPE_1, routeInfo.getFeatures().get(0)); - } - - @Test - public void testhasAnyFeaturesReturnsFalse() { - MediaRoute2Info routeInfo = new MediaRoute2Info.Builder(TEST_ID, TEST_NAME) - .addFeature(TEST_ROUTE_TYPE_0) - .addFeature(TEST_ROUTE_TYPE_1) - .build(); - - List<String> testRouteTypes = new ArrayList<>(); - testRouteTypes.add("non_matching_route_type_1"); - testRouteTypes.add("non_matching_route_type_2"); - testRouteTypes.add("non_matching_route_type_3"); - testRouteTypes.add("non_matching_route_type_4"); - - assertFalse(routeInfo.hasAnyFeatures(testRouteTypes)); - } - - @Test - public void testhasAnyFeaturesReturnsTrue() { - MediaRoute2Info routeInfo = new MediaRoute2Info.Builder(TEST_ID, TEST_NAME) - .addFeature(TEST_ROUTE_TYPE_0) - .addFeature(TEST_ROUTE_TYPE_1) - .build(); - - List<String> testRouteTypes = new ArrayList<>(); - testRouteTypes.add("non_matching_route_type_1"); - testRouteTypes.add("non_matching_route_type_2"); - testRouteTypes.add("non_matching_route_type_3"); - testRouteTypes.add(TEST_ROUTE_TYPE_1); - - assertTrue(routeInfo.hasAnyFeatures(testRouteTypes)); - } - - @Test - public void testEqualsCreatedWithSameArguments() { - Bundle extras = new Bundle(); - extras.putString(TEST_KEY, TEST_VALUE); - - MediaRoute2Info routeInfo1 = new MediaRoute2Info.Builder(TEST_ID, TEST_NAME) - .addFeature(TEST_ROUTE_TYPE_0) - .addFeature(TEST_ROUTE_TYPE_1) - .setDeviceType(TEST_DEVICE_TYPE) - .setIconUri(TEST_ICON_URI) - .setDescription(TEST_DESCRIPTION) - .setConnectionState(TEST_CONNECTION_STATE) - .setClientPackageName(TEST_CLIENT_PACKAGE_NAME) - .setVolumeHandling(TEST_VOLUME_HANDLING) - .setVolumeMax(TEST_VOLUME_MAX) - .setVolume(TEST_VOLUME) - .setExtras(extras) - .build(); - - MediaRoute2Info routeInfo2 = new MediaRoute2Info.Builder(TEST_ID, TEST_NAME) - .addFeature(TEST_ROUTE_TYPE_0) - .addFeature(TEST_ROUTE_TYPE_1) - .setDeviceType(TEST_DEVICE_TYPE) - .setIconUri(TEST_ICON_URI) - .setDescription(TEST_DESCRIPTION) - .setConnectionState(TEST_CONNECTION_STATE) - .setClientPackageName(TEST_CLIENT_PACKAGE_NAME) - .setVolumeHandling(TEST_VOLUME_HANDLING) - .setVolumeMax(TEST_VOLUME_MAX) - .setVolume(TEST_VOLUME) - .setExtras(extras) - .build(); - - assertEquals(routeInfo1, routeInfo2); - assertEquals(routeInfo1.hashCode(), routeInfo2.hashCode()); - } - - @Test - public void testEqualsCreatedWithBuilderCopyConstructor() { - Bundle extras = new Bundle(); - extras.putString(TEST_KEY, TEST_VALUE); - - MediaRoute2Info routeInfo1 = new MediaRoute2Info.Builder(TEST_ID, TEST_NAME) - .addFeature(TEST_ROUTE_TYPE_0) - .addFeature(TEST_ROUTE_TYPE_1) - .setDeviceType(TEST_DEVICE_TYPE) - .setIconUri(TEST_ICON_URI) - .setDescription(TEST_DESCRIPTION) - .setConnectionState(TEST_CONNECTION_STATE) - .setClientPackageName(TEST_CLIENT_PACKAGE_NAME) - .setVolumeHandling(TEST_VOLUME_HANDLING) - .setVolumeMax(TEST_VOLUME_MAX) - .setVolume(TEST_VOLUME) - .setExtras(extras) - .build(); - - MediaRoute2Info routeInfo2 = new MediaRoute2Info.Builder(routeInfo1).build(); - - assertEquals(routeInfo1, routeInfo2); - assertEquals(routeInfo1.hashCode(), routeInfo2.hashCode()); - } - - @Test - public void testEqualsReturnFalse() { - Bundle extras = new Bundle(); - extras.putString(TEST_KEY, TEST_VALUE); - - MediaRoute2Info routeInfo = new MediaRoute2Info.Builder(TEST_ID, TEST_NAME) - .addFeature(TEST_ROUTE_TYPE_0) - .addFeature(TEST_ROUTE_TYPE_1) - .setDeviceType(TEST_DEVICE_TYPE) - .setIconUri(TEST_ICON_URI) - .setDescription(TEST_DESCRIPTION) - .setConnectionState(TEST_CONNECTION_STATE) - .setClientPackageName(TEST_CLIENT_PACKAGE_NAME) - .setVolumeHandling(TEST_VOLUME_HANDLING) - .setVolumeMax(TEST_VOLUME_MAX) - .setVolume(TEST_VOLUME) - .setExtras(extras) - .build(); - - // Now, we will use copy constructor - assertNotEquals(routeInfo, new MediaRoute2Info.Builder(routeInfo) - .addFeature("randomRouteType") - .build()); - assertNotEquals(routeInfo, new MediaRoute2Info.Builder(routeInfo) - .setDeviceType(TEST_DEVICE_TYPE + 1) - .build()); - assertNotEquals(routeInfo, new MediaRoute2Info.Builder(routeInfo) - .setIconUri(Uri.parse("randomUri")) - .build()); - assertNotEquals(routeInfo, new MediaRoute2Info.Builder(routeInfo) - .setDescription("randomDescription") - .build()); - assertNotEquals(routeInfo, new MediaRoute2Info.Builder(routeInfo) - .setConnectionState(TEST_CONNECTION_STATE + 1) - .build()); - assertNotEquals(routeInfo, new MediaRoute2Info.Builder(routeInfo) - .setClientPackageName("randomPackageName") - .build()); - assertNotEquals(routeInfo, new MediaRoute2Info.Builder(routeInfo) - .setVolumeHandling(TEST_VOLUME_HANDLING + 1) - .build()); - assertNotEquals(routeInfo, new MediaRoute2Info.Builder(routeInfo) - .setVolumeMax(TEST_VOLUME_MAX + 100) - .build()); - assertNotEquals(routeInfo, new MediaRoute2Info.Builder(routeInfo) - .setVolume(TEST_VOLUME + 10) - .build()); - // Note: Extras will not affect the equals. - } - - @Test - public void testParcelingAndUnParceling() { - Bundle extras = new Bundle(); - extras.putString(TEST_KEY, TEST_VALUE); - - MediaRoute2Info routeInfo = new MediaRoute2Info.Builder(TEST_ID, TEST_NAME) - .addFeature(TEST_ROUTE_TYPE_0) - .addFeature(TEST_ROUTE_TYPE_1) - .setDeviceType(TEST_DEVICE_TYPE) - .setIconUri(TEST_ICON_URI) - .setDescription(TEST_DESCRIPTION) - .setConnectionState(TEST_CONNECTION_STATE) - .setClientPackageName(TEST_CLIENT_PACKAGE_NAME) - .setVolumeHandling(TEST_VOLUME_HANDLING) - .setVolumeMax(TEST_VOLUME_MAX) - .setVolume(TEST_VOLUME) - .setExtras(extras) - .build(); - - Parcel parcel = Parcel.obtain(); - routeInfo.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - - MediaRoute2Info routeInfoFromParcel = MediaRoute2Info.CREATOR.createFromParcel(parcel); - assertEquals(routeInfo, routeInfoFromParcel); - assertEquals(routeInfo.hashCode(), routeInfoFromParcel.hashCode()); - - // Check extras - Bundle extrasOut = routeInfoFromParcel.getExtras(); - assertNotNull(extrasOut); - assertTrue(extrasOut.containsKey(TEST_KEY)); - assertEquals(TEST_VALUE, extrasOut.getString(TEST_KEY)); - } -} diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java deleted file mode 100644 index e0b454559456..000000000000 --- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java +++ /dev/null @@ -1,780 +0,0 @@ -/* - * Copyright 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.mediaroutertest; - -import static android.media.MediaRoute2Info.CONNECTION_STATE_CONNECTING; -import static android.media.MediaRoute2Info.DEVICE_TYPE_REMOTE_SPEAKER; -import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE; - -import static com.android.mediaroutertest.MediaRouterManagerTest.FEATURES_ALL; -import static com.android.mediaroutertest.MediaRouterManagerTest.FEATURES_SPECIAL; -import static com.android.mediaroutertest.MediaRouterManagerTest.FEATURE_SAMPLE; -import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID1; -import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID2; -import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID3_SESSION_CREATION_FAILED; -import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID4_TO_SELECT_AND_DESELECT; -import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID5_TO_TRANSFER_TO; -import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID_SPECIAL_FEATURE; -import static com.android.mediaroutertest.MediaRouterManagerTest.ROUTE_ID_VARIABLE_VOLUME; -import static com.android.mediaroutertest.MediaRouterManagerTest.SYSTEM_PROVIDER_ID; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.testng.Assert.assertThrows; - -import android.annotation.NonNull; -import android.content.Context; -import android.media.MediaRoute2Info; -import android.media.MediaRouter2; -import android.media.MediaRouter2.OnGetControllerHintsListener; -import android.media.MediaRouter2.RouteCallback; -import android.media.MediaRouter2.RoutingController; -import android.media.MediaRouter2.RoutingControllerCallback; -import android.media.RouteDiscoveryPreference; -import android.net.Uri; -import android.os.Bundle; -import android.os.Parcel; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; -import android.text.TextUtils; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.function.Predicate; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public class MediaRouter2Test { - private static final String TAG = "MediaRouter2Test"; - Context mContext; - private MediaRouter2 mRouter2; - private Executor mExecutor; - - private static final int TIMEOUT_MS = 5000; - - private static final String TEST_KEY = "test_key"; - private static final String TEST_VALUE = "test_value"; - - @Before - public void setUp() throws Exception { - mContext = InstrumentationRegistry.getTargetContext(); - mRouter2 = MediaRouter2.getInstance(mContext); - mExecutor = Executors.newSingleThreadExecutor(); - } - - @After - public void tearDown() throws Exception { - } - - /** - * Tests if we get proper routes for application that has special route type. - */ - @Test - public void testGetRoutes() throws Exception { - Map<String, MediaRoute2Info> routes = waitAndGetRoutes(FEATURES_SPECIAL); - - assertEquals(1, routes.size()); - assertNotNull(routes.get(ROUTE_ID_SPECIAL_FEATURE)); - } - - @Test - public void testRouteInfoEquality() { - MediaRoute2Info routeInfo = new MediaRoute2Info.Builder("id", "name") - .setDescription("description") - .setClientPackageName("com.android.mediaroutertest") - .setConnectionState(CONNECTION_STATE_CONNECTING) - .setIconUri(new Uri.Builder().path("icon").build()) - .setVolume(5) - .setVolumeMax(20) - .addFeature(FEATURE_SAMPLE) - .setVolumeHandling(PLAYBACK_VOLUME_VARIABLE) - .setDeviceType(DEVICE_TYPE_REMOTE_SPEAKER) - .build(); - - MediaRoute2Info routeInfoRebuilt = new MediaRoute2Info.Builder(routeInfo).build(); - assertEquals(routeInfo, routeInfoRebuilt); - - Parcel parcel = Parcel.obtain(); - parcel.writeParcelable(routeInfo, 0); - parcel.setDataPosition(0); - MediaRoute2Info routeInfoFromParcel = parcel.readParcelable(null); - - assertEquals(routeInfo, routeInfoFromParcel); - } - - @Test - public void testControlVolumeWithRouter() throws Exception { - Map<String, MediaRoute2Info> routes = waitAndGetRoutes(FEATURES_ALL); - - MediaRoute2Info volRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME); - assertNotNull(volRoute); - - int originalVolume = volRoute.getVolume(); - int deltaVolume = (originalVolume == volRoute.getVolumeMax() ? -1 : 1); - - awaitOnRouteChanged( - () -> mRouter2.requestUpdateVolume(volRoute, deltaVolume), - ROUTE_ID_VARIABLE_VOLUME, - (route -> route.getVolume() == originalVolume + deltaVolume), - FEATURES_ALL); - - awaitOnRouteChanged( - () -> mRouter2.requestSetVolume(volRoute, originalVolume), - ROUTE_ID_VARIABLE_VOLUME, - (route -> route.getVolume() == originalVolume), - FEATURES_ALL); - } - - @Test - public void testRegisterControllerCallbackWithInvalidArguments() { - Executor executor = mExecutor; - RoutingControllerCallback callback = new RoutingControllerCallback(); - - // Tests null executor - assertThrows(NullPointerException.class, - () -> mRouter2.registerControllerCallback(null, callback)); - - // Tests null callback - assertThrows(NullPointerException.class, - () -> mRouter2.registerControllerCallback(executor, null)); - } - - @Test - public void testUnregisterControllerCallbackWithNullCallback() { - // Tests null callback - assertThrows(NullPointerException.class, - () -> mRouter2.unregisterControllerCallback(null)); - } - - @Test - public void testRequestCreateControllerWithNullRoute() { - assertThrows(NullPointerException.class, - () -> mRouter2.requestCreateController(null)); - } - - @Test - public void testRequestCreateControllerSuccess() throws Exception { - final List<String> sampleRouteFeature = new ArrayList<>(); - sampleRouteFeature.add(FEATURE_SAMPLE); - - Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteFeature); - MediaRoute2Info route = routes.get(ROUTE_ID1); - assertNotNull(route); - - final CountDownLatch successLatch = new CountDownLatch(1); - final CountDownLatch failureLatch = new CountDownLatch(1); - final List<RoutingController> controllers = new ArrayList<>(); - - // Create session with this route - RoutingControllerCallback controllerCallback = new RoutingControllerCallback() { - @Override - public void onControllerCreated(RoutingController controller) { - assertNotNull(controller); - assertTrue(createRouteMap(controller.getSelectedRoutes()).containsKey(ROUTE_ID1)); - controllers.add(controller); - successLatch.countDown(); - } - - @Override - public void onControllerCreationFailed(MediaRoute2Info requestedRoute) { - failureLatch.countDown(); - } - }; - - // TODO: Remove this once the MediaRouter2 becomes always connected to the service. - RouteCallback routeCallback = new RouteCallback(); - mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryPreference.EMPTY); - - try { - mRouter2.registerControllerCallback(mExecutor, controllerCallback); - mRouter2.requestCreateController(route); - assertTrue(successLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - - // onSessionCreationFailed should not be called. - assertFalse(failureLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - } finally { - releaseControllers(controllers); - mRouter2.unregisterRouteCallback(routeCallback); - mRouter2.unregisterControllerCallback(controllerCallback); - } - } - - @Test - public void testRequestCreateControllerFailure() throws Exception { - final List<String> sampleRouteType = new ArrayList<>(); - sampleRouteType.add(FEATURE_SAMPLE); - - Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType); - MediaRoute2Info route = routes.get(ROUTE_ID3_SESSION_CREATION_FAILED); - assertNotNull(route); - - final CountDownLatch successLatch = new CountDownLatch(1); - final CountDownLatch failureLatch = new CountDownLatch(1); - final List<RoutingController> controllers = new ArrayList<>(); - - // Create session with this route - RoutingControllerCallback controllerCallback = new RoutingControllerCallback() { - @Override - public void onControllerCreated(RoutingController controller) { - controllers.add(controller); - successLatch.countDown(); - } - - @Override - public void onControllerCreationFailed(MediaRoute2Info requestedRoute) { - assertEquals(route, requestedRoute); - failureLatch.countDown(); - } - }; - - // TODO: Remove this once the MediaRouter2 becomes always connected to the service. - RouteCallback routeCallback = new RouteCallback(); - mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryPreference.EMPTY); - - try { - mRouter2.registerControllerCallback(mExecutor, controllerCallback); - mRouter2.requestCreateController(route); - assertTrue(failureLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - - // onSessionCreated should not be called. - assertFalse(successLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - } finally { - releaseControllers(controllers); - mRouter2.unregisterRouteCallback(routeCallback); - mRouter2.unregisterControllerCallback(controllerCallback); - } - } - - @Test - public void testRequestCreateControllerMultipleSessions() throws Exception { - final List<String> sampleRouteType = new ArrayList<>(); - sampleRouteType.add(FEATURE_SAMPLE); - - final CountDownLatch successLatch = new CountDownLatch(2); - final CountDownLatch failureLatch = new CountDownLatch(1); - final List<RoutingController> createdControllers = new ArrayList<>(); - - // Create session with this route - RoutingControllerCallback controllerCallback = new RoutingControllerCallback() { - @Override - public void onControllerCreated(RoutingController controller) { - createdControllers.add(controller); - successLatch.countDown(); - } - - @Override - public void onControllerCreationFailed(MediaRoute2Info requestedRoute) { - failureLatch.countDown(); - } - }; - - Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType); - MediaRoute2Info route1 = routes.get(ROUTE_ID1); - MediaRoute2Info route2 = routes.get(ROUTE_ID2); - assertNotNull(route1); - assertNotNull(route2); - - // TODO: Remove this once the MediaRouter2 becomes always connected to the service. - RouteCallback routeCallback = new RouteCallback(); - mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryPreference.EMPTY); - - try { - mRouter2.registerControllerCallback(mExecutor, controllerCallback); - mRouter2.requestCreateController(route1); - mRouter2.requestCreateController(route2); - assertTrue(successLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - - // onSessionCreationFailed should not be called. - assertFalse(failureLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - - // Created controllers should have proper info - assertEquals(2, createdControllers.size()); - RoutingController controller1 = createdControllers.get(0); - RoutingController controller2 = createdControllers.get(1); - - assertNotEquals(controller1.getId(), controller2.getId()); - assertTrue(createRouteMap(controller1.getSelectedRoutes()).containsKey(ROUTE_ID1)); - assertTrue(createRouteMap(controller2.getSelectedRoutes()).containsKey(ROUTE_ID2)); - - } finally { - releaseControllers(createdControllers); - mRouter2.unregisterRouteCallback(routeCallback); - mRouter2.unregisterControllerCallback(controllerCallback); - } - } - - @Test - public void testSetOnGetControllerHintsListener() throws Exception { - final List<String> sampleRouteFeature = new ArrayList<>(); - sampleRouteFeature.add(FEATURE_SAMPLE); - - Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteFeature); - MediaRoute2Info route = routes.get(ROUTE_ID1); - assertNotNull(route); - - final Bundle createSessionHints = new Bundle(); - createSessionHints.putString(TEST_KEY, TEST_VALUE); - final OnGetControllerHintsListener listener = new OnGetControllerHintsListener() { - @Override - public Bundle onGetControllerHints(MediaRoute2Info route) { - return createSessionHints; - } - }; - - final CountDownLatch successLatch = new CountDownLatch(1); - final CountDownLatch failureLatch = new CountDownLatch(1); - final List<RoutingController> controllers = new ArrayList<>(); - - // Create session with this route - RoutingControllerCallback controllerCallback = new RoutingControllerCallback() { - @Override - public void onControllerCreated(RoutingController controller) { - assertNotNull(controller); - assertTrue(createRouteMap(controller.getSelectedRoutes()).containsKey(ROUTE_ID1)); - - // The SampleMediaRoute2ProviderService supposed to set control hints - // with the given creationSessionHints. - Bundle controlHints = controller.getControlHints(); - assertNotNull(controlHints); - assertTrue(controlHints.containsKey(TEST_KEY)); - assertEquals(TEST_VALUE, controlHints.getString(TEST_KEY)); - - controllers.add(controller); - successLatch.countDown(); - } - - @Override - public void onControllerCreationFailed(MediaRoute2Info requestedRoute) { - failureLatch.countDown(); - } - }; - - // TODO: Remove this once the MediaRouter2 becomes always connected to the service. - RouteCallback routeCallback = new RouteCallback(); - mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryPreference.EMPTY); - - try { - mRouter2.registerControllerCallback(mExecutor, controllerCallback); - - // The SampleMediaRoute2ProviderService supposed to set control hints - // with the given creationSessionHints. - mRouter2.setOnGetControllerHintsListener(listener); - mRouter2.requestCreateController(route); - assertTrue(successLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - - // onSessionCreationFailed should not be called. - assertFalse(failureLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - } finally { - releaseControllers(controllers); - mRouter2.unregisterRouteCallback(routeCallback); - mRouter2.unregisterControllerCallback(controllerCallback); - } - } - - @Test - public void testRoutingControllerCallbackIsNotCalledAfterUnregistered() throws Exception { - final List<String> sampleRouteType = new ArrayList<>(); - sampleRouteType.add(FEATURE_SAMPLE); - - Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType); - MediaRoute2Info route = routes.get(ROUTE_ID1); - assertNotNull(route); - - final CountDownLatch successLatch = new CountDownLatch(1); - final CountDownLatch failureLatch = new CountDownLatch(1); - final List<RoutingController> controllers = new ArrayList<>(); - - // Create session with this route - RoutingControllerCallback controllerCallback = new RoutingControllerCallback() { - @Override - public void onControllerCreated(RoutingController controller) { - controllers.add(controller); - successLatch.countDown(); - } - - @Override - public void onControllerCreationFailed(MediaRoute2Info requestedRoute) { - failureLatch.countDown(); - } - }; - - // TODO: Remove this once the MediaRouter2 becomes always connected to the service. - RouteCallback routeCallback = new RouteCallback(); - mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryPreference.EMPTY); - - try { - mRouter2.registerControllerCallback(mExecutor, controllerCallback); - mRouter2.requestCreateController(route); - - // Unregisters session callback - mRouter2.unregisterControllerCallback(controllerCallback); - - // No session callback methods should be called. - assertFalse(successLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - assertFalse(failureLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - } finally { - releaseControllers(controllers); - mRouter2.unregisterRouteCallback(routeCallback); - mRouter2.unregisterControllerCallback(controllerCallback); - } - } - - // TODO: Add tests for illegal inputs if needed (e.g. selecting already selected route) - @Test - public void testRoutingControllerSelectAndDeselectRoute() throws Exception { - final List<String> sampleRouteType = new ArrayList<>(); - sampleRouteType.add(FEATURE_SAMPLE); - - Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType); - MediaRoute2Info routeToCreateSessionWith = routes.get(ROUTE_ID1); - assertNotNull(routeToCreateSessionWith); - - final CountDownLatch onControllerCreatedLatch = new CountDownLatch(1); - final CountDownLatch onControllerUpdatedLatchForSelect = new CountDownLatch(1); - final CountDownLatch onControllerUpdatedLatchForDeselect = new CountDownLatch(1); - final List<RoutingController> controllers = new ArrayList<>(); - - // Create session with ROUTE_ID1 - RoutingControllerCallback controllerCallback = new RoutingControllerCallback() { - @Override - public void onControllerCreated(RoutingController controller) { - assertNotNull(controller); - assertTrue(getRouteIds(controller.getSelectedRoutes()).contains(ROUTE_ID1)); - controllers.add(controller); - onControllerCreatedLatch.countDown(); - } - - @Override - public void onControllerUpdated(RoutingController controller) { - if (onControllerCreatedLatch.getCount() != 0 - || !TextUtils.equals( - controllers.get(0).getId(), controller.getId())) { - return; - } - - if (onControllerUpdatedLatchForSelect.getCount() != 0) { - assertEquals(2, controller.getSelectedRoutes().size()); - assertTrue(getRouteIds(controller.getSelectedRoutes()) - .contains(ROUTE_ID1)); - assertTrue(getRouteIds(controller.getSelectedRoutes()) - .contains(ROUTE_ID4_TO_SELECT_AND_DESELECT)); - assertFalse(getRouteIds(controller.getSelectableRoutes()) - .contains(ROUTE_ID4_TO_SELECT_AND_DESELECT)); - - onControllerUpdatedLatchForSelect.countDown(); - } else { - assertEquals(1, controller.getSelectedRoutes().size()); - assertTrue(getRouteIds(controller.getSelectedRoutes()) - .contains(ROUTE_ID1)); - assertFalse(getRouteIds(controller.getSelectedRoutes()) - .contains(ROUTE_ID4_TO_SELECT_AND_DESELECT)); - assertTrue(getRouteIds(controller.getSelectableRoutes()) - .contains(ROUTE_ID4_TO_SELECT_AND_DESELECT)); - - onControllerUpdatedLatchForDeselect.countDown(); - } - } - }; - - // TODO: Remove this once the MediaRouter2 becomes always connected to the service. - RouteCallback routeCallback = new RouteCallback(); - mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryPreference.EMPTY); - - try { - mRouter2.registerControllerCallback(mExecutor, controllerCallback); - mRouter2.requestCreateController(routeToCreateSessionWith); - assertTrue(onControllerCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - - assertEquals(1, controllers.size()); - RoutingController controller = controllers.get(0); - assertTrue(getRouteIds(controller.getSelectableRoutes()) - .contains(ROUTE_ID4_TO_SELECT_AND_DESELECT)); - - // Select ROUTE_ID4_TO_SELECT_AND_DESELECT - MediaRoute2Info routeToSelectAndDeselect = routes.get( - ROUTE_ID4_TO_SELECT_AND_DESELECT); - assertNotNull(routeToSelectAndDeselect); - - controller.selectRoute(routeToSelectAndDeselect); - assertTrue(onControllerUpdatedLatchForSelect.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - - controller.deselectRoute(routeToSelectAndDeselect); - assertTrue(onControllerUpdatedLatchForDeselect.await( - TIMEOUT_MS, TimeUnit.MILLISECONDS)); - } finally { - releaseControllers(controllers); - mRouter2.unregisterRouteCallback(routeCallback); - mRouter2.unregisterControllerCallback(controllerCallback); - } - } - - @Test - public void testRoutingControllerTransferToRoute() throws Exception { - final List<String> sampleRouteType = new ArrayList<>(); - sampleRouteType.add(FEATURE_SAMPLE); - - Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType); - MediaRoute2Info routeToCreateSessionWith = routes.get(ROUTE_ID1); - assertNotNull(routeToCreateSessionWith); - - final CountDownLatch onControllerCreatedLatch = new CountDownLatch(1); - final CountDownLatch onControllerUpdatedLatch = new CountDownLatch(1); - final List<RoutingController> controllers = new ArrayList<>(); - - // Create session with ROUTE_ID1 - RoutingControllerCallback controllerCallback = new RoutingControllerCallback() { - @Override - public void onControllerCreated(RoutingController controller) { - assertNotNull(controller); - assertTrue(getRouteIds(controller.getSelectedRoutes()).contains(ROUTE_ID1)); - controllers.add(controller); - onControllerCreatedLatch.countDown(); - } - - @Override - public void onControllerUpdated(RoutingController controller) { - if (onControllerCreatedLatch.getCount() != 0 - || !TextUtils.equals( - controllers.get(0).getId(), controller.getId())) { - return; - } - assertEquals(1, controller.getSelectedRoutes().size()); - assertFalse(getRouteIds(controller.getSelectedRoutes()).contains(ROUTE_ID1)); - assertTrue(getRouteIds(controller.getSelectedRoutes()) - .contains(ROUTE_ID5_TO_TRANSFER_TO)); - assertFalse(getRouteIds(controller.getTransferrableRoutes()) - .contains(ROUTE_ID5_TO_TRANSFER_TO)); - - onControllerUpdatedLatch.countDown(); - } - }; - - // TODO: Remove this once the MediaRouter2 becomes always connected to the service. - RouteCallback routeCallback = new RouteCallback(); - mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryPreference.EMPTY); - - try { - mRouter2.registerControllerCallback(mExecutor, controllerCallback); - mRouter2.requestCreateController(routeToCreateSessionWith); - assertTrue(onControllerCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - - assertEquals(1, controllers.size()); - RoutingController controller = controllers.get(0); - assertTrue(getRouteIds(controller.getTransferrableRoutes()) - .contains(ROUTE_ID5_TO_TRANSFER_TO)); - - // Transfer to ROUTE_ID5_TO_TRANSFER_TO - MediaRoute2Info routeToTransferTo = routes.get(ROUTE_ID5_TO_TRANSFER_TO); - assertNotNull(routeToTransferTo); - - controller.transferToRoute(routeToTransferTo); - assertTrue(onControllerUpdatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - } finally { - releaseControllers(controllers); - mRouter2.unregisterRouteCallback(routeCallback); - mRouter2.unregisterControllerCallback(controllerCallback); - } - } - - // TODO: Add tests for onSessionReleased() when provider releases the session. - - @Test - public void testRoutingControllerRelease() throws Exception { - final List<String> sampleRouteType = new ArrayList<>(); - sampleRouteType.add(FEATURE_SAMPLE); - - Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType); - MediaRoute2Info routeToCreateSessionWith = routes.get(ROUTE_ID1); - assertNotNull(routeToCreateSessionWith); - - final CountDownLatch onControllerCreatedLatch = new CountDownLatch(1); - final CountDownLatch onControllerUpdatedLatch = new CountDownLatch(1); - final CountDownLatch onControllerReleasedLatch = new CountDownLatch(1); - final List<RoutingController> controllers = new ArrayList<>(); - - // Create session with ROUTE_ID1 - RoutingControllerCallback controllerCallback = new RoutingControllerCallback() { - @Override - public void onControllerCreated(RoutingController controller) { - assertNotNull(controller); - assertTrue(getRouteIds(controller.getSelectedRoutes()).contains(ROUTE_ID1)); - controllers.add(controller); - onControllerCreatedLatch.countDown(); - } - - @Override - public void onControllerUpdated(RoutingController controller) { - if (onControllerCreatedLatch.getCount() != 0 - || !TextUtils.equals(controllers.get(0).getId(), controller.getId())) { - return; - } - onControllerUpdatedLatch.countDown(); - } - - @Override - public void onControllerReleased(RoutingController controller) { - if (onControllerCreatedLatch.getCount() != 0 - || !TextUtils.equals(controllers.get(0).getId(), controller.getId())) { - return; - } - onControllerReleasedLatch.countDown(); - } - }; - - // TODO: Remove this once the MediaRouter2 becomes always connected to the service. - RouteCallback routeCallback = new RouteCallback(); - mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryPreference.EMPTY); - - try { - mRouter2.registerControllerCallback(mExecutor, controllerCallback); - mRouter2.requestCreateController(routeToCreateSessionWith); - assertTrue(onControllerCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - - assertEquals(1, controllers.size()); - RoutingController controller = controllers.get(0); - assertTrue(getRouteIds(controller.getTransferrableRoutes()) - .contains(ROUTE_ID5_TO_TRANSFER_TO)); - - // Release controller. Future calls should be ignored. - controller.release(); - - // Transfer to ROUTE_ID5_TO_TRANSFER_TO - MediaRoute2Info routeToTransferTo = routes.get(ROUTE_ID5_TO_TRANSFER_TO); - assertNotNull(routeToTransferTo); - - // This call should be ignored. - // The onSessionInfoChanged() shouldn't be called. - controller.transferToRoute(routeToTransferTo); - assertFalse(onControllerUpdatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - - // onControllerReleased should be called. - assertTrue(onControllerReleasedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - } finally { - releaseControllers(controllers); - mRouter2.unregisterRouteCallback(routeCallback); - mRouter2.unregisterControllerCallback(controllerCallback); - } - } - - // TODO: Consider adding tests with bluetooth connection/disconnection. - @Test - public void testGetSystemController() { - final RoutingController systemController = mRouter2.getSystemController(); - assertNotNull(systemController); - assertFalse(systemController.isReleased()); - } - - @Test - public void testControllers() { - List<RoutingController> controllers = mRouter2.getControllers(); - assertNotNull(controllers); - assertFalse(controllers.isEmpty()); - assertSame(mRouter2.getSystemController(), controllers.get(0)); - } - - // Helper for getting routes easily - static Map<String, MediaRoute2Info> createRouteMap(List<MediaRoute2Info> routes) { - Map<String, MediaRoute2Info> routeMap = new HashMap<>(); - for (MediaRoute2Info route : routes) { - routeMap.put(route.getId(), route); - } - return routeMap; - } - - Map<String, MediaRoute2Info> waitAndGetRoutes(List<String> routeTypes) - throws Exception { - CountDownLatch latch = new CountDownLatch(1); - - // A dummy callback is required to send route type info. - RouteCallback routeCallback = new RouteCallback() { - @Override - public void onRoutesAdded(List<MediaRoute2Info> routes) { - for (int i = 0; i < routes.size(); i++) { - //TODO: use isSystem() or similar method when it's ready - if (!TextUtils.equals(routes.get(i).getProviderId(), SYSTEM_PROVIDER_ID)) { - latch.countDown(); - } - } - } - }; - - mRouter2.registerRouteCallback(mExecutor, routeCallback, - new RouteDiscoveryPreference.Builder(routeTypes, true).build()); - try { - latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS); - return createRouteMap(mRouter2.getRoutes()); - } finally { - mRouter2.unregisterRouteCallback(routeCallback); - } - } - - static void releaseControllers(@NonNull List<RoutingController> controllers) { - for (RoutingController controller : controllers) { - controller.release(); - } - } - - /** - * Returns a list of IDs of the given route list. - */ - List<String> getRouteIds(@NonNull List<MediaRoute2Info> routes) { - List<String> result = new ArrayList<>(); - for (MediaRoute2Info route : routes) { - result.add(route.getId()); - } - return result; - } - - void awaitOnRouteChanged(Runnable task, String routeId, - Predicate<MediaRoute2Info> predicate, - List<String> routeTypes) throws Exception { - CountDownLatch latch = new CountDownLatch(1); - RouteCallback routeCallback = new RouteCallback() { - @Override - public void onRoutesChanged(List<MediaRoute2Info> changed) { - MediaRoute2Info route = createRouteMap(changed).get(routeId); - if (route != null && predicate.test(route)) { - latch.countDown(); - } - } - }; - mRouter2.registerRouteCallback(mExecutor, routeCallback, - new RouteDiscoveryPreference.Builder(routeTypes, true).build()); - try { - task.run(); - assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - } finally { - mRouter2.unregisterRouteCallback(routeCallback); - } - } -} diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/RouteDiscoveryPreferenceTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/RouteDiscoveryPreferenceTest.java deleted file mode 100644 index fa129350ed8b..000000000000 --- a/media/tests/MediaRouter/src/com/android/mediaroutertest/RouteDiscoveryPreferenceTest.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 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.mediaroutertest; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; - -import android.media.RouteDiscoveryPreference; -import android.os.Parcel; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.ArrayList; -import java.util.List; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public class RouteDiscoveryPreferenceTest { - @Before - public void setUp() throws Exception { } - - @After - public void tearDown() throws Exception { } - - @Test - public void testEquality() { - List<String> testTypes = new ArrayList<>(); - testTypes.add("TEST_TYPE_1"); - testTypes.add("TEST_TYPE_2"); - RouteDiscoveryPreference request = new RouteDiscoveryPreference.Builder(testTypes, true) - .build(); - - RouteDiscoveryPreference requestRebuilt = new RouteDiscoveryPreference.Builder(request) - .build(); - - assertEquals(request, requestRebuilt); - - Parcel parcel = Parcel.obtain(); - parcel.writeParcelable(request, 0); - parcel.setDataPosition(0); - RouteDiscoveryPreference requestFromParcel = parcel.readParcelable(null); - - assertEquals(request, requestFromParcel); - } - - @Test - public void testInequality() { - List<String> testTypes = new ArrayList<>(); - testTypes.add("TEST_TYPE_1"); - testTypes.add("TEST_TYPE_2"); - - List<String> testTypes2 = new ArrayList<>(); - testTypes.add("TEST_TYPE_3"); - - RouteDiscoveryPreference request = new RouteDiscoveryPreference.Builder(testTypes, true) - .build(); - - RouteDiscoveryPreference requestTypes = new RouteDiscoveryPreference.Builder(request) - .setPreferredFeatures(testTypes2) - .build(); - assertNotEquals(request, requestTypes); - - RouteDiscoveryPreference requestActiveScan = new RouteDiscoveryPreference.Builder(request) - .setActiveScan(false) - .build(); - assertNotEquals(request, requestActiveScan); - } -} diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/RoutingSessionInfoTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/RoutingSessionInfoTest.java deleted file mode 100644 index 704dca0427ed..000000000000 --- a/media/tests/MediaRouter/src/com/android/mediaroutertest/RoutingSessionInfoTest.java +++ /dev/null @@ -1,526 +0,0 @@ -/* - * Copyright 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.mediaroutertest; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.testng.Assert.assertThrows; - -import android.media.RoutingSessionInfo; -import android.os.Bundle; -import android.os.Parcel; -import android.support.test.filters.SmallTest; -import android.support.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Tests {@link RoutingSessionInfo} and its {@link RoutingSessionInfo.Builder builder}. - */ -@RunWith(AndroidJUnit4.class) -@SmallTest -public class RoutingSessionInfoTest { - public static final String TEST_ID = "test_id"; - public static final String TEST_CLIENT_PACKAGE_NAME = "com.test.client.package.name"; - public static final String TEST_ROUTE_FEATURE = "test_route_feature"; - - public static final String TEST_ROUTE_ID_0 = "test_route_type_0"; - public static final String TEST_ROUTE_ID_1 = "test_route_type_1"; - public static final String TEST_ROUTE_ID_2 = "test_route_type_2"; - public static final String TEST_ROUTE_ID_3 = "test_route_type_3"; - public static final String TEST_ROUTE_ID_4 = "test_route_type_4"; - public static final String TEST_ROUTE_ID_5 = "test_route_type_5"; - public static final String TEST_ROUTE_ID_6 = "test_route_type_6"; - public static final String TEST_ROUTE_ID_7 = "test_route_type_7"; - - public static final String TEST_KEY = "test_key"; - public static final String TEST_VALUE = "test_value"; - - @Test - public void testBuilderConstructorWithInvalidValues() { - final String nullId = null; - final String nullClientPackageName = null; - - final String emptyId = ""; - // Note: An empty string as client package name is valid. - - final String validId = TEST_ID; - final String validClientPackageName = TEST_CLIENT_PACKAGE_NAME; - - // ID is invalid - assertThrows(IllegalArgumentException.class, () -> new RoutingSessionInfo.Builder( - nullId, validClientPackageName)); - assertThrows(IllegalArgumentException.class, () -> new RoutingSessionInfo.Builder( - emptyId, validClientPackageName)); - - // client package name is invalid (null) - assertThrows(NullPointerException.class, () -> new RoutingSessionInfo.Builder( - validId, nullClientPackageName)); - - // Both are invalid - assertThrows(IllegalArgumentException.class, () -> new RoutingSessionInfo.Builder( - nullId, nullClientPackageName)); - assertThrows(IllegalArgumentException.class, () -> new RoutingSessionInfo.Builder( - emptyId, nullClientPackageName)); - } - - @Test - public void testBuilderCopyConstructorWithNull() { - // Null RouteInfo (1-argument constructor) - final RoutingSessionInfo nullRoutingSessionInfo = null; - assertThrows(NullPointerException.class, - () -> new RoutingSessionInfo.Builder(nullRoutingSessionInfo)); - } - - @Test - public void testBuilderConstructorWithEmptyClientPackageName() { - // An empty string for client package name is valid. (for unknown cases) - // Creating builder with it should not throw any exception. - RoutingSessionInfo.Builder builder = new RoutingSessionInfo.Builder( - TEST_ID, "" /* clientPackageName*/); - } - - @Test - public void testBuilderBuildWithEmptySelectedRoutesThrowsIAE() { - RoutingSessionInfo.Builder builder = new RoutingSessionInfo.Builder( - TEST_ID, TEST_CLIENT_PACKAGE_NAME); - // Note: Calling build() without adding any selected routes. - assertThrows(IllegalArgumentException.class, () -> builder.build()); - } - - @Test - public void testBuilderAddRouteMethodsWithIllegalArgumentsThrowsIAE() { - RoutingSessionInfo.Builder builder = new RoutingSessionInfo.Builder( - TEST_ID, TEST_CLIENT_PACKAGE_NAME); - - final String nullRouteId = null; - final String emptyRouteId = ""; - - assertThrows(IllegalArgumentException.class, - () -> builder.addSelectedRoute(nullRouteId)); - assertThrows(IllegalArgumentException.class, - () -> builder.addSelectableRoute(nullRouteId)); - assertThrows(IllegalArgumentException.class, - () -> builder.addDeselectableRoute(nullRouteId)); - assertThrows(IllegalArgumentException.class, - () -> builder.addTransferrableRoute(nullRouteId)); - - assertThrows(IllegalArgumentException.class, - () -> builder.addSelectedRoute(emptyRouteId)); - assertThrows(IllegalArgumentException.class, - () -> builder.addSelectableRoute(emptyRouteId)); - assertThrows(IllegalArgumentException.class, - () -> builder.addDeselectableRoute(emptyRouteId)); - assertThrows(IllegalArgumentException.class, - () -> builder.addTransferrableRoute(emptyRouteId)); - } - - @Test - public void testBuilderRemoveRouteMethodsWithIllegalArgumentsThrowsIAE() { - RoutingSessionInfo.Builder builder = new RoutingSessionInfo.Builder( - TEST_ID, TEST_CLIENT_PACKAGE_NAME); - - final String nullRouteId = null; - final String emptyRouteId = ""; - - assertThrows(IllegalArgumentException.class, - () -> builder.removeSelectedRoute(nullRouteId)); - assertThrows(IllegalArgumentException.class, - () -> builder.removeSelectableRoute(nullRouteId)); - assertThrows(IllegalArgumentException.class, - () -> builder.removeDeselectableRoute(nullRouteId)); - assertThrows(IllegalArgumentException.class, - () -> builder.removeTransferrableRoute(nullRouteId)); - - assertThrows(IllegalArgumentException.class, - () -> builder.removeSelectedRoute(emptyRouteId)); - assertThrows(IllegalArgumentException.class, - () -> builder.removeSelectableRoute(emptyRouteId)); - assertThrows(IllegalArgumentException.class, - () -> builder.removeDeselectableRoute(emptyRouteId)); - assertThrows(IllegalArgumentException.class, - () -> builder.removeTransferrableRoute(emptyRouteId)); - } - - @Test - public void testBuilderAndGettersOfRoutingSessionInfo() { - Bundle controlHints = new Bundle(); - controlHints.putString(TEST_KEY, TEST_VALUE); - - RoutingSessionInfo sessionInfo = new RoutingSessionInfo.Builder( - TEST_ID, TEST_CLIENT_PACKAGE_NAME) - .addSelectedRoute(TEST_ROUTE_ID_0) - .addSelectedRoute(TEST_ROUTE_ID_1) - .addSelectableRoute(TEST_ROUTE_ID_2) - .addSelectableRoute(TEST_ROUTE_ID_3) - .addDeselectableRoute(TEST_ROUTE_ID_4) - .addDeselectableRoute(TEST_ROUTE_ID_5) - .addTransferrableRoute(TEST_ROUTE_ID_6) - .addTransferrableRoute(TEST_ROUTE_ID_7) - .setControlHints(controlHints) - .build(); - - assertEquals(TEST_ID, sessionInfo.getId()); - assertEquals(TEST_CLIENT_PACKAGE_NAME, sessionInfo.getClientPackageName()); - - assertEquals(2, sessionInfo.getSelectedRoutes().size()); - assertEquals(TEST_ROUTE_ID_0, sessionInfo.getSelectedRoutes().get(0)); - assertEquals(TEST_ROUTE_ID_1, sessionInfo.getSelectedRoutes().get(1)); - - assertEquals(2, sessionInfo.getSelectableRoutes().size()); - assertEquals(TEST_ROUTE_ID_2, sessionInfo.getSelectableRoutes().get(0)); - assertEquals(TEST_ROUTE_ID_3, sessionInfo.getSelectableRoutes().get(1)); - - assertEquals(2, sessionInfo.getDeselectableRoutes().size()); - assertEquals(TEST_ROUTE_ID_4, sessionInfo.getDeselectableRoutes().get(0)); - assertEquals(TEST_ROUTE_ID_5, sessionInfo.getDeselectableRoutes().get(1)); - - assertEquals(2, sessionInfo.getTransferrableRoutes().size()); - assertEquals(TEST_ROUTE_ID_6, sessionInfo.getTransferrableRoutes().get(0)); - assertEquals(TEST_ROUTE_ID_7, sessionInfo.getTransferrableRoutes().get(1)); - - Bundle controlHintsOut = sessionInfo.getControlHints(); - assertNotNull(controlHintsOut); - assertTrue(controlHintsOut.containsKey(TEST_KEY)); - assertEquals(TEST_VALUE, controlHintsOut.getString(TEST_KEY)); - } - - @Test - public void testBuilderAddRouteMethodsWithBuilderCopyConstructor() { - RoutingSessionInfo sessionInfo = new RoutingSessionInfo.Builder( - TEST_ID, TEST_CLIENT_PACKAGE_NAME) - .addSelectedRoute(TEST_ROUTE_ID_0) - .addSelectableRoute(TEST_ROUTE_ID_2) - .addDeselectableRoute(TEST_ROUTE_ID_4) - .addTransferrableRoute(TEST_ROUTE_ID_6) - .build(); - - RoutingSessionInfo newSessionInfo = new RoutingSessionInfo.Builder(sessionInfo) - .addSelectedRoute(TEST_ROUTE_ID_1) - .addSelectableRoute(TEST_ROUTE_ID_3) - .addDeselectableRoute(TEST_ROUTE_ID_5) - .addTransferrableRoute(TEST_ROUTE_ID_7) - .build(); - - assertEquals(2, newSessionInfo.getSelectedRoutes().size()); - assertEquals(TEST_ROUTE_ID_0, newSessionInfo.getSelectedRoutes().get(0)); - assertEquals(TEST_ROUTE_ID_1, newSessionInfo.getSelectedRoutes().get(1)); - - assertEquals(2, newSessionInfo.getSelectableRoutes().size()); - assertEquals(TEST_ROUTE_ID_2, newSessionInfo.getSelectableRoutes().get(0)); - assertEquals(TEST_ROUTE_ID_3, newSessionInfo.getSelectableRoutes().get(1)); - - assertEquals(2, newSessionInfo.getDeselectableRoutes().size()); - assertEquals(TEST_ROUTE_ID_4, newSessionInfo.getDeselectableRoutes().get(0)); - assertEquals(TEST_ROUTE_ID_5, newSessionInfo.getDeselectableRoutes().get(1)); - - assertEquals(2, newSessionInfo.getTransferrableRoutes().size()); - assertEquals(TEST_ROUTE_ID_6, newSessionInfo.getTransferrableRoutes().get(0)); - assertEquals(TEST_ROUTE_ID_7, newSessionInfo.getTransferrableRoutes().get(1)); - } - - @Test - public void testBuilderRemoveRouteMethods() { - RoutingSessionInfo sessionInfo = new RoutingSessionInfo.Builder( - TEST_ID, TEST_CLIENT_PACKAGE_NAME) - .addSelectedRoute(TEST_ROUTE_ID_0) - .addSelectedRoute(TEST_ROUTE_ID_1) - .removeSelectedRoute(TEST_ROUTE_ID_1) - - .addSelectableRoute(TEST_ROUTE_ID_2) - .addSelectableRoute(TEST_ROUTE_ID_3) - .removeSelectableRoute(TEST_ROUTE_ID_3) - - .addDeselectableRoute(TEST_ROUTE_ID_4) - .addDeselectableRoute(TEST_ROUTE_ID_5) - .removeDeselectableRoute(TEST_ROUTE_ID_5) - - .addTransferrableRoute(TEST_ROUTE_ID_6) - .addTransferrableRoute(TEST_ROUTE_ID_7) - .removeTransferrableRoute(TEST_ROUTE_ID_7) - - .build(); - - assertEquals(1, sessionInfo.getSelectedRoutes().size()); - assertEquals(TEST_ROUTE_ID_0, sessionInfo.getSelectedRoutes().get(0)); - - assertEquals(1, sessionInfo.getSelectableRoutes().size()); - assertEquals(TEST_ROUTE_ID_2, sessionInfo.getSelectableRoutes().get(0)); - - assertEquals(1, sessionInfo.getDeselectableRoutes().size()); - assertEquals(TEST_ROUTE_ID_4, sessionInfo.getDeselectableRoutes().get(0)); - - assertEquals(1, sessionInfo.getTransferrableRoutes().size()); - assertEquals(TEST_ROUTE_ID_6, sessionInfo.getTransferrableRoutes().get(0)); - } - - @Test - public void testBuilderRemoveRouteMethodsWithBuilderCopyConstructor() { - RoutingSessionInfo sessionInfo = new RoutingSessionInfo.Builder( - TEST_ID, TEST_CLIENT_PACKAGE_NAME) - .addSelectedRoute(TEST_ROUTE_ID_0) - .addSelectedRoute(TEST_ROUTE_ID_1) - .addSelectableRoute(TEST_ROUTE_ID_2) - .addSelectableRoute(TEST_ROUTE_ID_3) - .addDeselectableRoute(TEST_ROUTE_ID_4) - .addDeselectableRoute(TEST_ROUTE_ID_5) - .addTransferrableRoute(TEST_ROUTE_ID_6) - .addTransferrableRoute(TEST_ROUTE_ID_7) - .build(); - - RoutingSessionInfo newSessionInfo = new RoutingSessionInfo.Builder(sessionInfo) - .removeSelectedRoute(TEST_ROUTE_ID_1) - .removeSelectableRoute(TEST_ROUTE_ID_3) - .removeDeselectableRoute(TEST_ROUTE_ID_5) - .removeTransferrableRoute(TEST_ROUTE_ID_7) - .build(); - - assertEquals(1, newSessionInfo.getSelectedRoutes().size()); - assertEquals(TEST_ROUTE_ID_0, newSessionInfo.getSelectedRoutes().get(0)); - - assertEquals(1, newSessionInfo.getSelectableRoutes().size()); - assertEquals(TEST_ROUTE_ID_2, newSessionInfo.getSelectableRoutes().get(0)); - - assertEquals(1, newSessionInfo.getDeselectableRoutes().size()); - assertEquals(TEST_ROUTE_ID_4, newSessionInfo.getDeselectableRoutes().get(0)); - - assertEquals(1, newSessionInfo.getTransferrableRoutes().size()); - assertEquals(TEST_ROUTE_ID_6, newSessionInfo.getTransferrableRoutes().get(0)); - } - - @Test - public void testBuilderClearRouteMethods() { - RoutingSessionInfo sessionInfo = new RoutingSessionInfo.Builder( - TEST_ID, TEST_CLIENT_PACKAGE_NAME) - .addSelectedRoute(TEST_ROUTE_ID_0) - .addSelectedRoute(TEST_ROUTE_ID_1) - .clearSelectedRoutes() - - .addSelectableRoute(TEST_ROUTE_ID_2) - .addSelectableRoute(TEST_ROUTE_ID_3) - .clearSelectableRoutes() - - .addDeselectableRoute(TEST_ROUTE_ID_4) - .addDeselectableRoute(TEST_ROUTE_ID_5) - .clearDeselectableRoutes() - - .addTransferrableRoute(TEST_ROUTE_ID_6) - .addTransferrableRoute(TEST_ROUTE_ID_7) - .clearTransferrableRoutes() - - // SelectedRoutes must not be empty - .addSelectedRoute(TEST_ROUTE_ID_0) - .build(); - - assertEquals(1, sessionInfo.getSelectedRoutes().size()); - assertEquals(TEST_ROUTE_ID_0, sessionInfo.getSelectedRoutes().get(0)); - - assertTrue(sessionInfo.getSelectableRoutes().isEmpty()); - assertTrue(sessionInfo.getDeselectableRoutes().isEmpty()); - assertTrue(sessionInfo.getTransferrableRoutes().isEmpty()); - } - - @Test - public void testBuilderClearRouteMethodsWithBuilderCopyConstructor() { - RoutingSessionInfo sessionInfo = new RoutingSessionInfo.Builder( - TEST_ID, TEST_CLIENT_PACKAGE_NAME) - .addSelectedRoute(TEST_ROUTE_ID_0) - .addSelectedRoute(TEST_ROUTE_ID_1) - .addSelectableRoute(TEST_ROUTE_ID_2) - .addSelectableRoute(TEST_ROUTE_ID_3) - .addDeselectableRoute(TEST_ROUTE_ID_4) - .addDeselectableRoute(TEST_ROUTE_ID_5) - .addTransferrableRoute(TEST_ROUTE_ID_6) - .addTransferrableRoute(TEST_ROUTE_ID_7) - .build(); - - RoutingSessionInfo newSessionInfo = new RoutingSessionInfo.Builder(sessionInfo) - .clearSelectedRoutes() - .clearSelectableRoutes() - .clearDeselectableRoutes() - .clearTransferrableRoutes() - // SelectedRoutes must not be empty - .addSelectedRoute(TEST_ROUTE_ID_0) - .build(); - - assertEquals(1, newSessionInfo.getSelectedRoutes().size()); - assertEquals(TEST_ROUTE_ID_0, newSessionInfo.getSelectedRoutes().get(0)); - - assertTrue(newSessionInfo.getSelectableRoutes().isEmpty()); - assertTrue(newSessionInfo.getDeselectableRoutes().isEmpty()); - assertTrue(newSessionInfo.getTransferrableRoutes().isEmpty()); - } - - @Test - public void testEqualsCreatedWithSameArguments() { - Bundle controlHints = new Bundle(); - controlHints.putString(TEST_KEY, TEST_VALUE); - - RoutingSessionInfo sessionInfo1 = new RoutingSessionInfo.Builder( - TEST_ID, TEST_CLIENT_PACKAGE_NAME) - .addSelectedRoute(TEST_ROUTE_ID_0) - .addSelectedRoute(TEST_ROUTE_ID_1) - .addSelectableRoute(TEST_ROUTE_ID_2) - .addSelectableRoute(TEST_ROUTE_ID_3) - .addDeselectableRoute(TEST_ROUTE_ID_4) - .addDeselectableRoute(TEST_ROUTE_ID_5) - .addTransferrableRoute(TEST_ROUTE_ID_6) - .addTransferrableRoute(TEST_ROUTE_ID_7) - .setControlHints(controlHints) - .build(); - - RoutingSessionInfo sessionInfo2 = new RoutingSessionInfo.Builder( - TEST_ID, TEST_CLIENT_PACKAGE_NAME) - .addSelectedRoute(TEST_ROUTE_ID_0) - .addSelectedRoute(TEST_ROUTE_ID_1) - .addSelectableRoute(TEST_ROUTE_ID_2) - .addSelectableRoute(TEST_ROUTE_ID_3) - .addDeselectableRoute(TEST_ROUTE_ID_4) - .addDeselectableRoute(TEST_ROUTE_ID_5) - .addTransferrableRoute(TEST_ROUTE_ID_6) - .addTransferrableRoute(TEST_ROUTE_ID_7) - .setControlHints(controlHints) - .build(); - - assertEquals(sessionInfo1, sessionInfo2); - assertEquals(sessionInfo1.hashCode(), sessionInfo2.hashCode()); - } - - @Test - public void testEqualsCreatedWithBuilderCopyConstructor() { - Bundle controlHints = new Bundle(); - controlHints.putString(TEST_KEY, TEST_VALUE); - - RoutingSessionInfo sessionInfo1 = new RoutingSessionInfo.Builder( - TEST_ID, TEST_CLIENT_PACKAGE_NAME) - .addSelectedRoute(TEST_ROUTE_ID_0) - .addSelectedRoute(TEST_ROUTE_ID_1) - .addSelectableRoute(TEST_ROUTE_ID_2) - .addSelectableRoute(TEST_ROUTE_ID_3) - .addDeselectableRoute(TEST_ROUTE_ID_4) - .addDeselectableRoute(TEST_ROUTE_ID_5) - .addTransferrableRoute(TEST_ROUTE_ID_6) - .addTransferrableRoute(TEST_ROUTE_ID_7) - .setControlHints(controlHints) - .build(); - - RoutingSessionInfo sessionInfo2 = new RoutingSessionInfo.Builder(sessionInfo1).build(); - - assertEquals(sessionInfo1, sessionInfo2); - assertEquals(sessionInfo1.hashCode(), sessionInfo2.hashCode()); - } - - @Test - public void testEqualsReturnFalse() { - Bundle controlHints = new Bundle(); - controlHints.putString(TEST_KEY, TEST_VALUE); - - RoutingSessionInfo sessionInfo = new RoutingSessionInfo.Builder( - TEST_ID, TEST_CLIENT_PACKAGE_NAME) - .addSelectedRoute(TEST_ROUTE_ID_0) - .addSelectedRoute(TEST_ROUTE_ID_1) - .addSelectableRoute(TEST_ROUTE_ID_2) - .addSelectableRoute(TEST_ROUTE_ID_3) - .addDeselectableRoute(TEST_ROUTE_ID_4) - .addDeselectableRoute(TEST_ROUTE_ID_5) - .addTransferrableRoute(TEST_ROUTE_ID_6) - .addTransferrableRoute(TEST_ROUTE_ID_7) - .setControlHints(controlHints) - .build(); - - // Now, we will use copy constructor - assertNotEquals(sessionInfo, new RoutingSessionInfo.Builder(sessionInfo) - .addSelectedRoute("randomRoute") - .build()); - assertNotEquals(sessionInfo, new RoutingSessionInfo.Builder(sessionInfo) - .addSelectableRoute("randomRoute") - .build()); - assertNotEquals(sessionInfo, new RoutingSessionInfo.Builder(sessionInfo) - .addDeselectableRoute("randomRoute") - .build()); - assertNotEquals(sessionInfo, new RoutingSessionInfo.Builder(sessionInfo) - .addTransferrableRoute("randomRoute") - .build()); - - assertNotEquals(sessionInfo, new RoutingSessionInfo.Builder(sessionInfo) - .removeSelectedRoute(TEST_ROUTE_ID_1) - .build()); - assertNotEquals(sessionInfo, new RoutingSessionInfo.Builder(sessionInfo) - .removeSelectableRoute(TEST_ROUTE_ID_3) - .build()); - assertNotEquals(sessionInfo, new RoutingSessionInfo.Builder(sessionInfo) - .removeDeselectableRoute(TEST_ROUTE_ID_5) - .build()); - assertNotEquals(sessionInfo, new RoutingSessionInfo.Builder(sessionInfo) - .removeTransferrableRoute(TEST_ROUTE_ID_7) - .build()); - - assertNotEquals(sessionInfo, new RoutingSessionInfo.Builder(sessionInfo) - .clearSelectedRoutes() - // Note: Calling build() with empty selected routes will throw IAE. - .addSelectedRoute(TEST_ROUTE_ID_0) - .build()); - assertNotEquals(sessionInfo, new RoutingSessionInfo.Builder(sessionInfo) - .clearSelectableRoutes() - .build()); - assertNotEquals(sessionInfo, new RoutingSessionInfo.Builder(sessionInfo) - .clearDeselectableRoutes() - .build()); - assertNotEquals(sessionInfo, new RoutingSessionInfo.Builder(sessionInfo) - .clearTransferrableRoutes() - .build()); - - // Note: ControlHints will not affect the equals. - } - - @Test - public void testParcelingAndUnParceling() { - Bundle controlHints = new Bundle(); - controlHints.putString(TEST_KEY, TEST_VALUE); - - RoutingSessionInfo sessionInfo = new RoutingSessionInfo.Builder( - TEST_ID, TEST_CLIENT_PACKAGE_NAME) - .addSelectedRoute(TEST_ROUTE_ID_0) - .addSelectedRoute(TEST_ROUTE_ID_1) - .addSelectableRoute(TEST_ROUTE_ID_2) - .addSelectableRoute(TEST_ROUTE_ID_3) - .addDeselectableRoute(TEST_ROUTE_ID_4) - .addDeselectableRoute(TEST_ROUTE_ID_5) - .addTransferrableRoute(TEST_ROUTE_ID_6) - .addTransferrableRoute(TEST_ROUTE_ID_7) - .setControlHints(controlHints) - .build(); - - Parcel parcel = Parcel.obtain(); - sessionInfo.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - - RoutingSessionInfo sessionInfoFromParcel = - RoutingSessionInfo.CREATOR.createFromParcel(parcel); - assertEquals(sessionInfo, sessionInfoFromParcel); - assertEquals(sessionInfo.hashCode(), sessionInfoFromParcel.hashCode()); - - // Check controlHints - Bundle controlHintsOut = sessionInfoFromParcel.getControlHints(); - assertNotNull(controlHintsOut); - assertTrue(controlHintsOut.containsKey(TEST_KEY)); - assertEquals(TEST_VALUE, controlHintsOut.getString(TEST_KEY)); - } -} diff --git a/mms/java/android/telephony/MmsManager.java b/mms/java/android/telephony/MmsManager.java index cf55eba6e5ba..f07cd5e34062 100644 --- a/mms/java/android/telephony/MmsManager.java +++ b/mms/java/android/telephony/MmsManager.java @@ -55,10 +55,12 @@ public class MmsManager { * sending the message. * @param sentIntent if not NULL this <code>PendingIntent</code> is broadcast when the message * is successfully sent, or failed + * @param messageId an id that uniquely identifies the message requested to be sent. + * Used for logging and diagnostics purposes. The id may be 0. */ public void sendMultimediaMessage(int subId, @NonNull Uri contentUri, @Nullable String locationUrl, @Nullable Bundle configOverrides, - @Nullable PendingIntent sentIntent) { + @Nullable PendingIntent sentIntent, long messageId) { try { final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); if (iMms == null) { @@ -66,7 +68,7 @@ public class MmsManager { } iMms.sendMessage(subId, ActivityThread.currentPackageName(), contentUri, - locationUrl, configOverrides, sentIntent); + locationUrl, configOverrides, sentIntent, messageId); } catch (RemoteException e) { // Ignore it } @@ -83,18 +85,22 @@ public class MmsManager { * downloading the message. * @param downloadedIntent if not NULL this <code>PendingIntent</code> is * broadcast when the message is downloaded, or the download is failed + * @param messageId an id that uniquely identifies the message requested to be downloaded. + * Used for logging and diagnostics purposes. The id may be 0. + * downloaded. * @throws IllegalArgumentException if locationUrl or contentUri is empty */ public void downloadMultimediaMessage(int subId, @NonNull String locationUrl, @NonNull Uri contentUri, @Nullable Bundle configOverrides, - @Nullable PendingIntent downloadedIntent) { + @Nullable PendingIntent downloadedIntent, long messageId) { try { final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms")); if (iMms == null) { return; } iMms.downloadMessage(subId, ActivityThread.currentPackageName(), - locationUrl, contentUri, configOverrides, downloadedIntent); + locationUrl, contentUri, configOverrides, downloadedIntent, + messageId); } catch (RemoteException e) { // Ignore it } diff --git a/mms/java/com/android/internal/telephony/IMms.aidl b/mms/java/com/android/internal/telephony/IMms.aidl index 8be511186800..e0e0a4a812e4 100644 --- a/mms/java/com/android/internal/telephony/IMms.aidl +++ b/mms/java/com/android/internal/telephony/IMms.aidl @@ -37,9 +37,11 @@ interface IMms { * sending the message. See {@link android.telephony.SmsManager} for the value names and types. * @param sentIntent if not NULL this <code>PendingIntent</code> is * broadcast when the message is successfully sent, or failed + * @param messageId An id that uniquely identifies the message requested to be sent. */ void sendMessage(int subId, String callingPkg, in Uri contentUri, - String locationUrl, in Bundle configOverrides, in PendingIntent sentIntent); + String locationUrl, in Bundle configOverrides, in PendingIntent sentIntent, + in long messageId); /** * Download an MMS message using known location and transaction id @@ -54,10 +56,11 @@ interface IMms { * types. * @param downloadedIntent if not NULL this <code>PendingIntent</code> is * broadcast when the message is downloaded, or the download is failed - */ + * @param messageId An id that uniquely identifies the message requested to be downloaded. + */ void downloadMessage(int subId, String callingPkg, String locationUrl, in Uri contentUri, in Bundle configOverrides, - in PendingIntent downloadedIntent); + in PendingIntent downloadedIntent, in long messageId); /** * Import a text message into system's SMS store diff --git a/packages/SettingsLib/res/values-ar/arrays.xml b/packages/SettingsLib/res/values-ar/arrays.xml index 851a3d8f136a..d65d821e71ab 100644 --- a/packages/SettingsLib/res/values-ar/arrays.xml +++ b/packages/SettingsLib/res/values-ar/arrays.xml @@ -252,7 +252,7 @@ <item msgid="3474333938380896988">"عرض مناطق العجز في رؤية اللونين الأخضر والأحمر"</item> </string-array> <string-array name="app_process_limit_entries"> - <item msgid="794656271086646068">"الحد القياسي"</item> + <item msgid="794656271086646068">"الحدّ العادي"</item> <item msgid="8628438298170567201">"ليست هناك عمليات بالخلفية"</item> <item msgid="915752993383950932">"عملية واحدة بحد أقصى"</item> <item msgid="8554877790859095133">"عمليتان بحد أقصى"</item> diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml index 54856566e021..5103345401f4 100644 --- a/packages/SettingsLib/res/values-ar/strings.xml +++ b/packages/SettingsLib/res/values-ar/strings.xml @@ -124,7 +124,7 @@ <string name="bluetooth_talkback_headset" msgid="3406852564400882682">"سماعة رأس"</string> <string name="bluetooth_talkback_phone" msgid="868393783858123880">"هاتف"</string> <string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"تصوير"</string> - <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"سماعة أذن"</string> + <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"السمّاعة"</string> <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"جهاز إدخال طرفي"</string> <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"بلوتوث"</string> <string name="bluetooth_hearingaid_left_pairing_message" msgid="8561855779703533591">"جارٍ إقران سماعة الأذن الطبية اليسرى…"</string> @@ -157,7 +157,7 @@ <string name="tts_settings" msgid="8130616705989351312">"إعدادات تحويل النص إلى كلام"</string> <string name="tts_settings_title" msgid="7602210956640483039">"تحويل النص إلى كلام"</string> <string name="tts_default_rate_title" msgid="3964187817364304022">"معدل سرعة الكلام"</string> - <string name="tts_default_rate_summary" msgid="3781937042151716987">"سرعة نطق الكلام"</string> + <string name="tts_default_rate_summary" msgid="3781937042151716987">"سرعة قول الكلام"</string> <string name="tts_default_pitch_title" msgid="6988592215554485479">"درجة الصوت"</string> <string name="tts_default_pitch_summary" msgid="9132719475281551884">"للتأثير في نبرة الكلام المُرَكَّب"</string> <string name="tts_default_lang_title" msgid="4698933575028098940">"اللغة"</string> @@ -181,7 +181,7 @@ <string name="tts_engine_preference_section_title" msgid="3861562305498624904">"المحرّك المفضّل"</string> <string name="tts_general_section_title" msgid="8919671529502364567">"عامة"</string> <string name="tts_reset_speech_pitch_title" msgid="7149398585468413246">"إعادة ضبط طبقة صوت الكلام"</string> - <string name="tts_reset_speech_pitch_summary" msgid="6822904157021406449">"إعادة ضبط طبقة الصوت التي يتم نطق النص بها على الإعداد التلقائي."</string> + <string name="tts_reset_speech_pitch_summary" msgid="6822904157021406449">"إعادة ضبط طبقة الصوت التي يتم قول النص بها على الإعداد التلقائي."</string> <string-array name="tts_rate_entries"> <item msgid="9004239613505400644">"بطيء جدًا"</item> <item msgid="1815382991399815061">"بطيء"</item> @@ -353,7 +353,7 @@ <string-array name="color_mode_names"> <item msgid="3836559907767149216">"نابض بالحياة (تلقائي)"</item> <item msgid="9112200311983078311">"طبيعي"</item> - <item msgid="6564241960833766170">"قياسي"</item> + <item msgid="6564241960833766170">"عادي"</item> </string-array> <string-array name="color_mode_descriptions"> <item msgid="6828141153199944847">"ألوان محسَّنة"</item> diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml index cda42d348c45..5bcff5ad27b2 100644 --- a/packages/SettingsLib/res/values-vi/strings.xml +++ b/packages/SettingsLib/res/values-vi/strings.xml @@ -201,7 +201,7 @@ <string name="development_settings_summary" msgid="8718917813868735095">"Đặt tùy chọn cho phát triển ứng dụng"</string> <string name="development_settings_not_available" msgid="355070198089140951">"Tùy chọn dành cho nhà phát triển không khả dụng cho người dùng này"</string> <string name="vpn_settings_not_available" msgid="2894137119965668920">"Cài đặt VPN không khả dụng cho người dùng này"</string> - <string name="tethering_settings_not_available" msgid="266821736434699780">"Cài đặt chia sẻ kết nối không khả dụng cho người dùng này"</string> + <string name="tethering_settings_not_available" msgid="266821736434699780">"Cài đặt cách chia sẻ kết nối không khả dụng cho người dùng này"</string> <string name="apn_settings_not_available" msgid="1147111671403342300">"Cài đặt tên điểm truy cập không khả dụng cho người dùng này"</string> <string name="enable_adb" msgid="8072776357237289039">"Gỡ lỗi qua USB"</string> <string name="enable_adb_summary" msgid="3711526030096574316">"Bật chế độ gỡ lỗi khi kết nối USB"</string> diff --git a/packages/SettingsLib/src/com/android/settingslib/NetworkPolicyEditor.java b/packages/SettingsLib/src/com/android/settingslib/NetworkPolicyEditor.java index b01fc8541957..f5aa652f3194 100644 --- a/packages/SettingsLib/src/com/android/settingslib/NetworkPolicyEditor.java +++ b/packages/SettingsLib/src/com/android/settingslib/NetworkPolicyEditor.java @@ -216,7 +216,7 @@ public class NetworkPolicyEditor { private static NetworkTemplate buildUnquotedNetworkTemplate(NetworkTemplate template) { if (template == null) return null; final String networkId = template.getNetworkId(); - final String strippedNetworkId = WifiInfo.removeDoubleQuotes(networkId); + final String strippedNetworkId = WifiInfo.sanitizeSsid(networkId); if (!TextUtils.equals(strippedNetworkId, networkId)) { return new NetworkTemplate( template.getMatchRule(), template.getSubscriberId(), strippedNetworkId); diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index 65269c9d5a89..dee1d7eced66 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -728,6 +728,7 @@ public class SettingsBackupTest { Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE, Settings.Secure.FACE_UNLOCK_RE_ENROLL, Settings.Secure.TAP_GESTURE, + Settings.Secure.NEARBY_SHARING_COMPONENT, // not user configurable Settings.Secure.WINDOW_MAGNIFICATION, Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_MAGNIFICATION_CONTROLLER, Settings.Secure.SUPPRESS_DOZE); diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index c238d7d49f9b..de174b13a459 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -69,10 +69,6 @@ android_library { ], manifest: "AndroidManifest.xml", - libs: [ - "telephony-common", - ], - kotlincflags: ["-Xjvm-default=enable"], plugins: ["dagger2-compiler-2.19"], @@ -136,7 +132,6 @@ android_library { ], libs: [ "android.test.runner", - "telephony-common", "android.test.base", ], kotlincflags: ["-Xjvm-default=enable"], @@ -163,10 +158,6 @@ android_app { proguard_flags_files: ["proguard.flags"], }, - libs: [ - "telephony-common", - ], - kotlincflags: ["-Xjvm-default=enable"], dxflags: ["--multi-dex"], diff --git a/packages/SystemUI/docs/plugin_hooks.md b/packages/SystemUI/docs/plugin_hooks.md index 2fb0c996111a..9fe2e181971a 100644 --- a/packages/SystemUI/docs/plugin_hooks.md +++ b/packages/SystemUI/docs/plugin_hooks.md @@ -56,11 +56,6 @@ Expected interface: [ClockPlugin](/packages/SystemUI/plugin/src/com/android/syst Use: Allows replacement of the keyguard main clock. -### Action: com.android.systemui.action.PLUGIN_NPV -Expected interface: [NPVPlugin](/packages/SystemUI/plugin/src/com/android/systemui/plugins/NPVPlugin.java) - -Use: Attach a view under QQS for prototyping. - # Global plugin dependencies These classes can be accessed by any plugin using PluginDependency as long as they @Requires them. diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/HomeControlsPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/HomeControlsPlugin.java deleted file mode 100644 index c1d4b03b6620..000000000000 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/HomeControlsPlugin.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.systemui.plugins; - -import android.view.ViewGroup; - -import com.android.systemui.plugins.annotations.ProvidesInterface; - -/** - * Test plugin for home controls - */ -@ProvidesInterface(action = HomeControlsPlugin.ACTION, version = HomeControlsPlugin.VERSION) -public interface HomeControlsPlugin extends Plugin { - - String ACTION = "com.android.systemui.action.PLUGIN_HOME_CONTROLS"; - int VERSION = 1; - - /** - * Pass the container for the plugin to use however it wants. Ideally the plugin impl - * will add home controls to this space. - */ - void sendParentGroup(ViewGroup group); - - /** - * When visible, will poll for updates. - */ - void setVisible(boolean visible); -} diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/NPVPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/NPVPlugin.java deleted file mode 100644 index 1426266a7048..000000000000 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/NPVPlugin.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.plugins; - -import android.view.View; -import android.widget.FrameLayout; - -import com.android.systemui.plugins.annotations.ProvidesInterface; - -/** - * Plugin to attach custom views under QQS. - * - * A parent view is provided to the plugin to which they can add Views. - * <br> - * The parent is a {@link FrameLayout} with same background as QS and 96dp height. - * - * {@see NPVPluginManager} - * {@see status_bar_expanded_plugin_frame} - */ -@ProvidesInterface(action = NPVPlugin.ACTION, version = NPVPlugin.VERSION) -public interface NPVPlugin extends Plugin { - String ACTION = "com.android.systemui.action.PLUGIN_NPV"; - int VERSION = 1; - - /** - * Attach views to the parent. - * - * @param parent a {@link FrameLayout} to which to attach views. Preferably a root view. - * @return a view attached to parent. - */ - View attachToRoot(FrameLayout parent); - - /** - * Indicate to the plugin when it is listening (QS expanded) - * @param listening - */ - default void setListening(boolean listening) {}; -} diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java index 17f2f476c9f2..6518924ca0c2 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java @@ -133,7 +133,6 @@ public interface QSTile { public CharSequence label; public CharSequence secondaryLabel; public CharSequence contentDescription; - public CharSequence stateDescription; public CharSequence dualLabelContentDescription; public boolean disabledByPolicy; public boolean dualTarget = false; @@ -152,7 +151,6 @@ public interface QSTile { || !Objects.equals(other.label, label) || !Objects.equals(other.secondaryLabel, secondaryLabel) || !Objects.equals(other.contentDescription, contentDescription) - || !Objects.equals(other.stateDescription, stateDescription) || !Objects.equals(other.dualLabelContentDescription, dualLabelContentDescription) || !Objects.equals(other.expandedAccessibilityClassName, @@ -170,7 +168,6 @@ public interface QSTile { other.label = label; other.secondaryLabel = secondaryLabel; other.contentDescription = contentDescription; - other.stateDescription = stateDescription; other.dualLabelContentDescription = dualLabelContentDescription; other.expandedAccessibilityClassName = expandedAccessibilityClassName; other.disabledByPolicy = disabledByPolicy; @@ -198,7 +195,6 @@ public interface QSTile { sb.append(",label=").append(label); sb.append(",secondaryLabel=").append(secondaryLabel); sb.append(",contentDescription=").append(contentDescription); - sb.append(",stateDescription=").append(stateDescription); sb.append(",dualLabelContentDescription=").append(dualLabelContentDescription); sb.append(",expandedAccessibilityClassName=").append(expandedAccessibilityClassName); sb.append(",disabledByPolicy=").append(disabledByPolicy); diff --git a/packages/SystemUI/res/drawable/control_no_favorites_background.xml b/packages/SystemUI/res/drawable/control_no_favorites_background.xml index 1e282ad0eec7..947c77b4e39e 100644 --- a/packages/SystemUI/res/drawable/control_no_favorites_background.xml +++ b/packages/SystemUI/res/drawable/control_no_favorites_background.xml @@ -17,6 +17,6 @@ */ --> <shape xmlns:android="http://schemas.android.com/apk/res/android"> - <stroke android:width="1dp" android:color="?android:attr/colorBackgroundFloating"/> + <stroke android:width="1dp" android:color="@*android:color/foreground_material_dark"/> <corners android:radius="@dimen/control_corner_radius" /> </shape> diff --git a/packages/SystemUI/res/layout/controls_base_item.xml b/packages/SystemUI/res/layout/controls_base_item.xml index 3c4c61e30bc1..cd7ec5eb5c81 100644 --- a/packages/SystemUI/res/layout/controls_base_item.xml +++ b/packages/SystemUI/res/layout/controls_base_item.xml @@ -23,8 +23,8 @@ android:padding="@dimen/control_padding" android:clickable="true" android:focusable="true" - android:layout_marginLeft="3dp" - android:layout_marginRight="3dp" + android:layout_marginLeft="2dp" + android:layout_marginRight="2dp" android:background="@drawable/control_background"> <ImageView @@ -60,9 +60,9 @@ android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:textSize="18sp" + android:textSize="14sp" android:textColor="?android:attr/textColorPrimary" - android:fontFamily="@*android:string/config_headlineFontFamily" + android:textAppearance="?android:attr/textAppearanceSmall" app:layout_constraintBottom_toTopOf="@+id/subtitle" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/icon" /> @@ -71,9 +71,9 @@ android:id="@+id/subtitle" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:textSize="16sp" + android:textSize="12sp" android:textColor="?android:attr/textColorSecondary" - android:fontFamily="@*android:string/config_headlineFontFamily" + android:textAppearance="?android:attr/textAppearanceSmall" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> diff --git a/packages/SystemUI/res/layout/controls_no_favorites.xml b/packages/SystemUI/res/layout/controls_no_favorites.xml index 79672caed61b..096f1f49aaba 100644 --- a/packages/SystemUI/res/layout/controls_no_favorites.xml +++ b/packages/SystemUI/res/layout/controls_no_favorites.xml @@ -12,7 +12,7 @@ android:paddingBottom="40dp" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" - android:textColor="?android:attr/textColorPrimary" + android:textColor="@*android:color/foreground_material_dark" android:fontFamily="@*android:string/config_headlineFontFamily" android:background="@drawable/control_no_favorites_background"/> </merge> diff --git a/packages/SystemUI/res/layout/controls_with_favorites.xml b/packages/SystemUI/res/layout/controls_with_favorites.xml index 7804fe6b6272..6a3e95d34358 100644 --- a/packages/SystemUI/res/layout/controls_with_favorites.xml +++ b/packages/SystemUI/res/layout/controls_with_favorites.xml @@ -4,7 +4,8 @@ <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" - android:layout_height="wrap_content"> + android:layout_height="wrap_content" + android:paddingBottom="20dp"> <TextView android:text="@string/quick_controls_title" @@ -13,17 +14,23 @@ android:singleLine="true" android:gravity="center" android:textSize="25dp" - android:textColor="?android:attr/textColorPrimary" + android:textColor="@*android:color/foreground_material_dark" android:fontFamily="@*android:string/config_headlineFontFamily" - app:layout_constraintLeft_toLeftOf="parent" - app:layout_constraintRight_toRightOf="parent"/> + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + <ImageView android:id="@+id/controls_more" android:src="@drawable/ic_more_vert" android:layout_width="34dp" android:layout_height="24dp" android:layout_marginEnd="10dp" - app:layout_constraintEnd_toEndOf="parent"/> + android:tint="@*android:color/foreground_material_dark" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> diff --git a/packages/SystemUI/res/layout/global_actions_grid_v2.xml b/packages/SystemUI/res/layout/global_actions_grid_v2.xml index 674148495478..f90012d790e0 100644 --- a/packages/SystemUI/res/layout/global_actions_grid_v2.xml +++ b/packages/SystemUI/res/layout/global_actions_grid_v2.xml @@ -96,18 +96,18 @@ app:layout_constraintTop_toBottomOf="@id/global_actions_view"> <FrameLayout - android:translationY="@dimen/global_actions_plugin_offset" android:id="@+id/global_actions_panel_container" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout> <LinearLayout - android:translationY="@dimen/global_actions_plugin_offset" android:id="@+id/global_actions_controls" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" + android:layout_marginRight="@dimen/global_actions_grid_horizontal_padding" + android:layout_marginLeft="@dimen/global_actions_grid_horizontal_padding" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@id/global_actions_panel"> diff --git a/packages/SystemUI/res/layout/home_controls.xml b/packages/SystemUI/res/layout/home_controls.xml deleted file mode 100644 index 69a0e872dc8c..000000000000 --- a/packages/SystemUI/res/layout/home_controls.xml +++ /dev/null @@ -1,12 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<FrameLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/home_controls_layout" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="@integer/notification_panel_layout_gravity" - android:visibility="gone" - android:padding="8dp" - android:layout_margin="5dp" - android:background="?android:attr/colorBackgroundFloating"> -</FrameLayout> diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml index 76c1045ef1dd..4fae3c500a45 100644 --- a/packages/SystemUI/res/layout/status_bar.xml +++ b/packages/SystemUI/res/layout/status_bar.xml @@ -42,32 +42,6 @@ android:visibility="gone" /> - <LinearLayout - android:id="@+id/divider_container" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="horizontal" - android:background="@color/transparent" > - - <android.widget.Space - android:layout_height="match_parent" - android:layout_width="0dp" - android:layout_weight="@integer/qqs_split_fraction" /> - - <com.android.systemui.DarkReceiverImpl - android:id="@+id/divider" - android:layout_height="match_parent" - android:layout_width="1dp" - android:layout_marginTop="4dp" - android:layout_marginBottom="4dp" /> - - <android.widget.Space - android:layout_height="match_parent" - android:layout_width="0dp" - android:layout_weight="@integer/qs_split_fraction" /> - - </LinearLayout> - <LinearLayout android:id="@+id/status_bar_contents" android:layout_width="match_parent" android:layout_height="match_parent" diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml index 479f255b7e44..115b4a86b86d 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -55,9 +55,6 @@ android:clipChildren="false" systemui:viewType="com.android.systemui.plugins.qs.QS" /> - <!-- Temporary area to test out home controls --> - <include layout="@layout/home_controls" /> - <com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout android:id="@+id/notification_stack_scroller" android:layout_marginTop="@dimen/notification_panel_margin_top" diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index cc58b2014496..1f9fb0511d26 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -972,7 +972,6 @@ <!-- Global actions power menu --> <dimen name="global_actions_top_margin">12dp</dimen> - <dimen name="global_actions_plugin_offset">-145dp</dimen> <dimen name="global_actions_panel_width">120dp</dimen> <dimen name="global_actions_padding">12dp</dimen> @@ -1182,7 +1181,7 @@ <dimen name="magnifier_up_down_controls_height">40dp</dimen> <!-- Home Controls --> - <dimen name="control_spacing">5dp</dimen> + <dimen name="control_spacing">4dp</dimen> <dimen name="control_corner_radius">15dp</dimen> <dimen name="control_height">100dp</dimen> <dimen name="control_padding">15dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 8d935ecc691d..1f13f8dc02fe 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2549,7 +2549,4 @@ <!-- Quick Controls strings [CHAR LIMIT=30] --> <string name="quick_controls_title">Quick Controls</string> - - <!-- The tile in quick settings is unavailable. [CHAR LIMIT=32] --> - <string name="tile_unavailable">Unvailable</string> </resources> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/IconLoader.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/IconLoader.java deleted file mode 100644 index 78b1b26140d5..000000000000 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/IconLoader.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.systemui.shared.recents.model; - -import static android.content.pm.PackageManager.MATCH_ANY_USER; - -import android.app.ActivityManager; -import android.content.ComponentName; -import android.content.Context; -import android.content.pm.ActivityInfo; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.os.UserHandle; -import android.util.IconDrawableFactory; -import android.util.Log; -import android.util.LruCache; - -import com.android.systemui.shared.system.PackageManagerWrapper; - -public abstract class IconLoader { - - private static final String TAG = "IconLoader"; - - protected final Context mContext; - protected final TaskKeyLruCache<Drawable> mIconCache; - protected final LruCache<ComponentName, ActivityInfo> mActivityInfoCache; - - public IconLoader(Context context, TaskKeyLruCache<Drawable> iconCache, LruCache<ComponentName, - ActivityInfo> activityInfoCache) { - mContext = context; - mIconCache = iconCache; - mActivityInfoCache = activityInfoCache; - } - - /** - * Returns the activity info for the given task key, retrieving one from the system if the - * task key is expired. - * - * TODO: Move this to an ActivityInfoCache class - */ - public ActivityInfo getAndUpdateActivityInfo(Task.TaskKey taskKey) { - ComponentName cn = taskKey.getComponent(); - ActivityInfo activityInfo = mActivityInfoCache.get(cn); - if (activityInfo == null) { - activityInfo = PackageManagerWrapper.getInstance().getActivityInfo(cn, taskKey.userId); - if (cn == null || activityInfo == null) { - Log.e(TAG, "Unexpected null component name or activity info: " + cn + ", " + - activityInfo); - return null; - } - mActivityInfoCache.put(cn, activityInfo); - } - return activityInfo; - } - - public Drawable getIcon(Task t) { - Drawable cachedIcon = mIconCache.get(t.key); - if (cachedIcon == null) { - cachedIcon = createNewIconForTask(t.key, t.taskDescription, true /* returnDefault */); - mIconCache.put(t.key, cachedIcon); - } - return cachedIcon; - } - - /** - * Returns the cached task icon if the task key is not expired, updating the cache if it is. - */ - public Drawable getAndInvalidateIfModified(Task.TaskKey taskKey, - ActivityManager.TaskDescription td, boolean loadIfNotCached) { - // Return the cached activity icon if it exists - Drawable icon = mIconCache.getAndInvalidateIfModified(taskKey); - if (icon != null) { - return icon; - } - - if (loadIfNotCached) { - icon = createNewIconForTask(taskKey, td, false /* returnDefault */); - if (icon != null) { - mIconCache.put(taskKey, icon); - return icon; - } - } - - // We couldn't load any icon - return null; - } - - private Drawable createNewIconForTask(Task.TaskKey taskKey, - ActivityManager.TaskDescription desc, boolean returnDefault) { - int userId = taskKey.userId; - Bitmap tdIcon = desc.getInMemoryIcon(); - if (tdIcon != null) { - return createDrawableFromBitmap(tdIcon, userId, desc); - } - if (desc.getIconResource() != 0) { - try { - PackageManager pm = mContext.getPackageManager(); - ApplicationInfo appInfo = pm.getApplicationInfo(taskKey.getPackageName(), - MATCH_ANY_USER); - Resources res = pm.getResourcesForApplication(appInfo); - return createBadgedDrawable(res.getDrawable(desc.getIconResource(), null), userId, - desc); - } catch (Resources.NotFoundException|PackageManager.NameNotFoundException e) { - Log.e(TAG, "Could not find icon drawable from resource", e); - } - } - - tdIcon = ActivityManager.TaskDescription.loadTaskDescriptionIcon( - desc.getIconFilename(), userId); - if (tdIcon != null) { - return createDrawableFromBitmap(tdIcon, userId, desc); - } - - // Load the icon from the activity info and cache it - ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey); - if (activityInfo != null) { - Drawable icon = getBadgedActivityIcon(activityInfo, userId, desc); - if (icon != null) { - return icon; - } - } - - // At this point, even if we can't load the icon, we will set the default icon. - return returnDefault ? getDefaultIcon(userId) : null; - } - - public abstract Drawable getDefaultIcon(int userId); - - protected Drawable createDrawableFromBitmap(Bitmap icon, int userId, - ActivityManager.TaskDescription desc) { - return createBadgedDrawable( - new BitmapDrawable(mContext.getResources(), icon), userId, desc); - } - - protected abstract Drawable createBadgedDrawable(Drawable icon, int userId, - ActivityManager.TaskDescription desc); - - /** - * @return the activity icon for the ActivityInfo for a user, badging if necessary. - */ - protected abstract Drawable getBadgedActivityIcon(ActivityInfo info, int userId, - ActivityManager.TaskDescription desc); - - public static class DefaultIconLoader extends IconLoader { - - private final BitmapDrawable mDefaultIcon; - private final IconDrawableFactory mDrawableFactory; - - public DefaultIconLoader(Context context, TaskKeyLruCache<Drawable> iconCache, - LruCache<ComponentName, ActivityInfo> activityInfoCache) { - super(context, iconCache, activityInfoCache); - - // Create the default assets - Bitmap icon = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8); - icon.eraseColor(0); - mDefaultIcon = new BitmapDrawable(context.getResources(), icon); - mDrawableFactory = IconDrawableFactory.newInstance(context); - } - - @Override - public Drawable getDefaultIcon(int userId) { - return mDefaultIcon; - } - - @Override - protected Drawable createBadgedDrawable(Drawable icon, int userId, - ActivityManager.TaskDescription desc) { - if (userId != UserHandle.myUserId()) { - icon = mContext.getPackageManager().getUserBadgedIcon(icon, new UserHandle(userId)); - } - return icon; - } - - @Override - protected Drawable getBadgedActivityIcon(ActivityInfo info, int userId, - ActivityManager.TaskDescription desc) { - return mDrawableFactory.getBadgedIcon(info, info.applicationInfo, userId); - } - } -} diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyCache.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyCache.java deleted file mode 100644 index 8a244bf81c7c..000000000000 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyCache.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.systemui.shared.recents.model; - -import android.util.Log; -import android.util.SparseArray; - -import com.android.systemui.shared.recents.model.Task.TaskKey; - -import java.util.ArrayList; -import java.util.Collection; - -/** - * Base class for both strong and LRU task key cache. - */ -public abstract class TaskKeyCache<V> { - - protected static final String TAG = "TaskKeyCache"; - - protected final SparseArray<TaskKey> mKeys = new SparseArray<>(); - - /** - * Gets a specific entry in the cache with the specified key, regardless of whether the cached - * value is valid or not. - */ - public final synchronized V get(TaskKey key) { - return getCacheEntry(key.id); - } - - /** - * Returns the value only if the key is valid (has not been updated since the last time it was - * in the cache) - */ - public final synchronized V getAndInvalidateIfModified(TaskKey key) { - TaskKey lastKey = mKeys.get(key.id); - if (lastKey != null) { - if ((lastKey.windowingMode != key.windowingMode) || - (lastKey.lastActiveTime != key.lastActiveTime)) { - // The task has updated (been made active since the last time it was put into the - // LRU cache) or the stack id for the task has changed, invalidate that cache item - remove(key); - return null; - } - } - // Either the task does not exist in the cache, or the last active time is the same as - // the key specified, so return what is in the cache - return getCacheEntry(key.id); - } - - /** Puts an entry in the cache for a specific key. */ - public final synchronized void put(TaskKey key, V value) { - if (key == null || value == null) { - Log.e(TAG, "Unexpected null key or value: " + key + ", " + value); - return; - } - mKeys.put(key.id, key); - putCacheEntry(key.id, value); - } - - - /** Removes a cache entry for a specific key. */ - public final synchronized void remove(TaskKey key) { - // Remove the key after the cache value because we need it to make the callback - removeCacheEntry(key.id); - mKeys.remove(key.id); - } - - /** @return {@link Collection} of {@link TaskKey} */ - public Collection<TaskKey> getValues() { - Collection<TaskKey> result = new ArrayList<>(mKeys.size()); - for (int i = 0; i < mKeys.size(); i++) { - result.add(mKeys.valueAt(i)); - } - return result; - } - - /** Removes all the entries in the cache. */ - public final synchronized void evictAll() { - evictAllCache(); - mKeys.clear(); - } - - protected abstract V getCacheEntry(int id); - protected abstract void putCacheEntry(int id, V value); - protected abstract void removeCacheEntry(int id); - protected abstract void evictAllCache(); -} diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java deleted file mode 100644 index bc57b08236cf..000000000000 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskKeyLruCache.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.shared.recents.model; - -import android.util.LruCache; - -import com.android.systemui.shared.recents.model.Task.TaskKey; - -import java.io.PrintWriter; - -/** - * A mapping of {@link TaskKey} to value, with additional LRU functionality where the least - * recently referenced key/values will be evicted as more values than the given cache size are - * inserted. - * - * In addition, this also allows the caller to invalidate cached values for keys that have since - * changed. - */ -public class TaskKeyLruCache<V> extends TaskKeyCache<V> { - - public interface EvictionCallback { - void onEntryEvicted(TaskKey key); - } - - private final LruCache<Integer, V> mCache; - private final EvictionCallback mEvictionCallback; - - public TaskKeyLruCache(int cacheSize) { - this(cacheSize, null); - } - - public TaskKeyLruCache(int cacheSize, EvictionCallback evictionCallback) { - mEvictionCallback = evictionCallback; - mCache = new LruCache<Integer, V>(cacheSize) { - - @Override - protected void entryRemoved(boolean evicted, Integer taskId, V oldV, V newV) { - if (mEvictionCallback != null && evicted) { - mEvictionCallback.onEntryEvicted(mKeys.get(taskId)); - } - - // Only remove from mKeys on cache remove, not a cache update. - if (newV == null) { - mKeys.remove(taskId); - } - } - }; - } - - /** Trims the cache to a specific size */ - public final void trimToSize(int cacheSize) { - mCache.trimToSize(cacheSize); - } - - public void dump(String prefix, PrintWriter writer) { - String innerPrefix = prefix + " "; - - writer.print(prefix); writer.print(TAG); - writer.print(" numEntries="); writer.print(mKeys.size()); - writer.println(); - int keyCount = mKeys.size(); - for (int i = 0; i < keyCount; i++) { - writer.print(innerPrefix); writer.println(mKeys.get(mKeys.keyAt(i))); - } - } - - @Override - protected V getCacheEntry(int id) { - return mCache.get(id); - } - - @Override - protected void putCacheEntry(int id, V value) { - mCache.put(id, value); - } - - @Override - protected void removeCacheEntry(int id) { - mCache.remove(id); - } - - @Override - protected void evictAllCache() { - mCache.evictAll(); - } -} diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java index ed1cd8191092..d5a08dda9853 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java @@ -409,15 +409,6 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback { mAudioManager.dispatchMediaKeyEvent(keyEvent); } - @Override - public void dispatchSystemUiVisibilityChanged(int visibility) { - super.dispatchSystemUiVisibilityChanged(visibility); - - if (!(mContext instanceof Activity)) { - setSystemUiVisibility(STATUS_BAR_DISABLE_BACK); - } - } - /** * In general, we enable unlocking the insecure keyguard with the menu key. However, there are * some cases where we wish to disable it, notably when the menu button placement or technology diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index ae787260adca..29c67ae1b4a6 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -15,7 +15,12 @@ */ package com.android.keyguard; +import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL; +import static android.view.ViewRootImpl.sNewInsetsMode; +import static android.view.WindowInsets.Type.ime; +import static android.view.WindowInsets.Type.systemBars; import static com.android.systemui.DejankUtils.whitelistIpcs; +import static java.lang.Integer.max; import android.app.Activity; import android.app.AlertDialog; @@ -38,6 +43,7 @@ import android.view.SurfaceControl; import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; +import android.view.WindowInsets; import android.view.WindowManager; import android.widget.FrameLayout; @@ -339,13 +345,22 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe } @Override - protected boolean fitSystemWindows(Rect insets) { + public WindowInsets onApplyWindowInsets(WindowInsets insets) { + // Consume bottom insets because we're setting the padding locally (for IME and navbar.) - setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), insets.bottom); - insets.bottom = 0; - return false; + int inset; + if (sNewInsetsMode == NEW_INSETS_MODE_FULL) { + int bottomInset = insets.getInsetsIgnoringVisibility(systemBars()).bottom; + int imeInset = insets.getInsets(ime()).bottom; + inset = max(bottomInset, imeInset); + } else { + inset = insets.getSystemWindowInsetBottom(); + } + setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), inset); + return insets.inset(0, 0, 0, inset); } + private void showDialog(String title, String message) { if (mAlertDialog != null) { mAlertDialog.dismiss(); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 58a6c17e8239..4e2f7d4ee862 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -371,7 +371,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab checkIsHandlerThread(); if (DEBUG_SIM_STATES) { Log.v(TAG, "onSubscriptionInfoChanged()"); - List<SubscriptionInfo> sil = mSubscriptionManager.getActiveSubscriptionInfoList(false); + List<SubscriptionInfo> sil = mSubscriptionManager + .getActiveAndHiddenSubscriptionInfoList(); if (sil != null) { for (SubscriptionInfo subInfo : sil) { Log.v(TAG, "SubInfo:" + subInfo); @@ -425,10 +426,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab public List<SubscriptionInfo> getSubscriptionInfo(boolean forceReload) { List<SubscriptionInfo> sil = mSubscriptionInfo; if (sil == null || forceReload) { - sil = mSubscriptionManager.getActiveSubscriptionInfoList(false); + sil = mSubscriptionManager.getActiveAndHiddenSubscriptionInfoList(); } if (sil == null) { - // getActiveSubscriptionInfoList was null callers expect an empty list. + // getActiveAndHiddenSubscriptionInfoList was null callers expect an empty list. mSubscriptionInfo = new ArrayList<SubscriptionInfo>(); } else { mSubscriptionInfo = sil; diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java index c243309d960a..581cf7a2fbef 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java @@ -86,6 +86,8 @@ public class WindowMagnificationController implements View.OnClickListener, private SurfaceView mMirrorSurfaceView; private View mControlsView; private View mOverlayView; + // The boundary of magnification frame. + private final Rect mMagnificationFrameBoundary = new Rect(); private MoveMirrorRunnable mMoveMirrorRunnable = new MoveMirrorRunnable(); @@ -93,7 +95,7 @@ public class WindowMagnificationController implements View.OnClickListener, mContext = context; mHandler = handler; Display display = mContext.getDisplay(); - display.getSize(mDisplaySize); + display.getRealSize(mDisplaySize); mDisplayId = mContext.getDisplayId(); mWm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); @@ -114,6 +116,7 @@ public class WindowMagnificationController implements View.OnClickListener, return; } setInitialStartBounds(); + setMagnificationFrameBoundary(); createOverlayWindow(); } @@ -330,7 +333,7 @@ public class WindowMagnificationController implements View.OnClickListener, @Override public void onClick(View v) { setMoveOffset(v, mMoveFrameAmountShort); - moveMirrorFromControls(); + moveMirrorWindow(mMoveWindowOffset.x, mMoveWindowOffset.y); } @Override @@ -370,10 +373,8 @@ public class WindowMagnificationController implements View.OnClickListener, case MotionEvent.ACTION_MOVE: int xDiff = (int) (event.getRawX() - mLastDrag.x); int yDiff = (int) (event.getRawY() - mLastDrag.y); - mMagnificationFrame.offset(xDiff, yDiff); + moveMirrorWindow(xDiff, yDiff); mLastDrag.set(event.getRawX(), event.getRawY()); - modifyWindowMagnification(mTransaction); - mTransaction.apply(); return true; } return false; @@ -393,11 +394,11 @@ public class WindowMagnificationController implements View.OnClickListener, } } - private void moveMirrorFromControls() { - mMagnificationFrame.offset(mMoveWindowOffset.x, mMoveWindowOffset.y); - - modifyWindowMagnification(mTransaction); - mTransaction.apply(); + private void moveMirrorWindow(int xOffset, int yOffset) { + if (updateMagnificationFramePosition(xOffset, yOffset)) { + modifyWindowMagnification(mTransaction); + mTransaction.apply(); + } } /** @@ -414,6 +415,52 @@ public class WindowMagnificationController implements View.OnClickListener, return new Rect(left, top, right, bottom); } + private void setMagnificationFrameBoundary() { + // Calculates width and height for magnification frame could exceed out the screen. + // TODO : re-calculating again when scale is changed. + // The half width of magnification frame. + final int halfWidth = mMagnificationFrame.width() / 2; + // The half height of magnification frame. + final int halfHeight = mMagnificationFrame.height() / 2; + // The scaled half width of magnified region. + final int scaledWidth = (int) (halfWidth / mScale); + // The scaled half height of magnified region. + final int scaledHeight = (int) (halfHeight / mScale); + final int exceededWidth = halfWidth - scaledWidth; + final int exceededHeight = halfHeight - scaledHeight; + + mMagnificationFrameBoundary.set(-exceededWidth, -exceededHeight, + mDisplaySize.x + exceededWidth, mDisplaySize.y + exceededHeight); + } + + /** + * Calculates and sets the real position of magnification frame based on the magnified region + * should be limited by the region of the display. + */ + private boolean updateMagnificationFramePosition(int xOffset, int yOffset) { + mTmpRect.set(mMagnificationFrame); + mTmpRect.offset(xOffset, yOffset); + + if (mTmpRect.left < mMagnificationFrameBoundary.left) { + mTmpRect.offsetTo(mMagnificationFrameBoundary.left, mTmpRect.top); + } else if (mTmpRect.right > mMagnificationFrameBoundary.right) { + final int leftOffset = mMagnificationFrameBoundary.right - mMagnificationFrame.width(); + mTmpRect.offsetTo(leftOffset, mTmpRect.top); + } + + if (mTmpRect.top < mMagnificationFrameBoundary.top) { + mTmpRect.offsetTo(mTmpRect.left, mMagnificationFrameBoundary.top); + } else if (mTmpRect.bottom > mMagnificationFrameBoundary.bottom) { + final int topOffset = mMagnificationFrameBoundary.bottom - mMagnificationFrame.height(); + mTmpRect.offsetTo(mTmpRect.left, topOffset); + } + + if (!mTmpRect.equals(mMagnificationFrame)) { + mMagnificationFrame.set(mTmpRect); + return true; + } + return false; + } @Override public void surfaceCreated(SurfaceHolder holder) { createMirror(); @@ -431,7 +478,7 @@ public class WindowMagnificationController implements View.OnClickListener, @Override public void run() { if (mIsPressedDown) { - moveMirrorFromControls(); + moveMirrorWindow(mMoveWindowOffset.x, mMoveWindowOffset.y); mHandler.postDelayed(mMoveMirrorRunnable, 100); } } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt index 926fb6e75594..40a93d69fef4 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt @@ -29,6 +29,8 @@ import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.LinearLayout +import android.widget.Space import android.widget.TextView import com.android.systemui.controls.controller.ControlsController @@ -144,10 +146,17 @@ class ControlsUiControllerImpl @Inject constructor ( inflater.inflate(R.layout.controls_no_favorites, parent, true) val textView = parent.requireViewById(R.id.controls_title) as TextView - textView.setOnClickListener { + textView.setOnClickListener(launchSelectorActivityListener(context)) + } + + private fun launchSelectorActivityListener(context: Context): (View) -> Unit { + return { _ -> + val closeDialog = Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS) + context.sendBroadcast(closeDialog) + val i = Intent() i.setComponent(ComponentName(context, ControlsProviderSelectorActivity::class.java)) - i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK) context.startActivity(i) } } @@ -171,13 +180,12 @@ class ControlsUiControllerImpl @Inject constructor ( controlViewsById.put(it.controlId, cvh) } - val moreImageView = parent.requireViewById(R.id.controls_more) as View - moreImageView.setOnClickListener { - val i = Intent() - i.setComponent(ComponentName(context, ControlsProviderSelectorActivity::class.java)) - i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) - context.startActivity(i) + if ((controlInfos.size % 2) == 1) { + lastRow.addView(Space(context), LinearLayout.LayoutParams(0, 0, 1f)) } + + val moreImageView = parent.requireViewById(R.id.controls_more) as View + moreImageView.setOnClickListener(launchSelectorActivityListener(context)) } override fun hide() { diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeEvent.java b/packages/SystemUI/src/com/android/systemui/doze/DozeEvent.java deleted file mode 100644 index d2fe39424875..000000000000 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeEvent.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.doze; - -import android.annotation.IntDef; - -import com.android.systemui.log.RichEvent; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * An event related to dozing. {@link DozeLog} stores and prints these events for debugging - * and triaging purposes. - */ -public class DozeEvent extends RichEvent { - /** - * Initializes a doze event - */ - public DozeEvent init(@EventType int type, String reason) { - super.init(DEBUG, type, reason); - return this; - } - - /** - * Event labels for each doze event - * Index corresponds to the integer associated with each {@link EventType} - */ - @Override - public String[] getEventLabels() { - final String[] events = new String[]{ - "PickupWakeup", - "PulseStart", - "PulseFinish", - "NotificationPulse", - "Dozing", - "Fling", - "EmergencyCall", - "KeyguardBouncerChanged", - "ScreenOn", - "ScreenOff", - "MissedTick", - "TimeTickScheduled", - "KeyguardVisibilityChanged", - "DozeStateChanged", - "WakeDisplay", - "ProximityResult", - "PulseDropped", - "PulseDisabledByProx", - "SensorTriggered" - }; - - if (events.length != TOTAL_EVENT_TYPES) { - throw new IllegalStateException("DozeEvent events.length should match TOTAL_EVENT_TYPES" - + " events.length=" + events.length - + " TOTAL_EVENT_LENGTH=" + TOTAL_EVENT_TYPES); - } - return events; - } - - /** - * Converts the reason (integer) to a user-readable string - */ - public static String reasonToString(@Reason int pulseReason) { - switch (pulseReason) { - case PULSE_REASON_INTENT: return "intent"; - case PULSE_REASON_NOTIFICATION: return "notification"; - case PULSE_REASON_SENSOR_SIGMOTION: return "sigmotion"; - case REASON_SENSOR_PICKUP: return "pickup"; - case REASON_SENSOR_DOUBLE_TAP: return "doubletap"; - case PULSE_REASON_SENSOR_LONG_PRESS: return "longpress"; - case PULSE_REASON_DOCKING: return "docking"; - case PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN: return "wakelockscreen"; - case REASON_SENSOR_WAKE_UP: return "wakeup"; - case REASON_SENSOR_TAP: return "tap"; - default: throw new IllegalArgumentException("invalid reason: " + pulseReason); - } - } - - @IntDef({PICKUP_WAKEUP, PULSE_START, PULSE_FINISH, NOTIFICATION_PULSE, DOZING, FLING, - EMERGENCY_CALL, KEYGUARD_BOUNCER_CHANGED, SCREEN_ON, SCREEN_OFF, MISSED_TICK, - TIME_TICK_SCHEDULED, KEYGUARD_VISIBILITY_CHANGE, DOZE_STATE_CHANGED, WAKE_DISPLAY, - PROXIMITY_RESULT, PULSE_DROPPED, PULSE_DISABLED_BY_PROX, SENSOR_TRIGGERED}) - /** - * Types of DozeEvents - */ - @Retention(RetentionPolicy.SOURCE) - public @interface EventType {} - public static final int PICKUP_WAKEUP = 0; - public static final int PULSE_START = 1; - public static final int PULSE_FINISH = 2; - public static final int NOTIFICATION_PULSE = 3; - public static final int DOZING = 4; - public static final int FLING = 5; - public static final int EMERGENCY_CALL = 6; - public static final int KEYGUARD_BOUNCER_CHANGED = 7; - public static final int SCREEN_ON = 8; - public static final int SCREEN_OFF = 9; - public static final int MISSED_TICK = 10; - public static final int TIME_TICK_SCHEDULED = 11; - public static final int KEYGUARD_VISIBILITY_CHANGE = 12; - public static final int DOZE_STATE_CHANGED = 13; - public static final int WAKE_DISPLAY = 14; - public static final int PROXIMITY_RESULT = 15; - public static final int PULSE_DROPPED = 16; - public static final int PULSE_DISABLED_BY_PROX = 17; - public static final int SENSOR_TRIGGERED = 18; - public static final int TOTAL_EVENT_TYPES = 19; - - public static final int TOTAL_REASONS = 10; - @IntDef({PULSE_REASON_NONE, PULSE_REASON_INTENT, PULSE_REASON_NOTIFICATION, - PULSE_REASON_SENSOR_SIGMOTION, REASON_SENSOR_PICKUP, REASON_SENSOR_DOUBLE_TAP, - PULSE_REASON_SENSOR_LONG_PRESS, PULSE_REASON_DOCKING, REASON_SENSOR_WAKE_UP, - PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN, REASON_SENSOR_TAP}) - @Retention(RetentionPolicy.SOURCE) - public @interface Reason {} - public static final int PULSE_REASON_NONE = -1; - public static final int PULSE_REASON_INTENT = 0; - public static final int PULSE_REASON_NOTIFICATION = 1; - public static final int PULSE_REASON_SENSOR_SIGMOTION = 2; - public static final int REASON_SENSOR_PICKUP = 3; - public static final int REASON_SENSOR_DOUBLE_TAP = 4; - public static final int PULSE_REASON_SENSOR_LONG_PRESS = 5; - public static final int PULSE_REASON_DOCKING = 6; - public static final int REASON_SENSOR_WAKE_UP = 7; - public static final int PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN = 8; - public static final int REASON_SENSOR_TAP = 9; -} diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java index fe504216b166..8afdf1aeb023 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java @@ -16,15 +16,20 @@ package com.android.systemui.doze; +import android.annotation.IntDef; import android.util.TimeUtils; +import androidx.annotation.NonNull; + import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.DumpController; -import com.android.systemui.log.SysuiLog; +import com.android.systemui.Dumpable; +import java.io.FileDescriptor; import java.io.PrintWriter; -import java.util.Date; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import javax.inject.Inject; import javax.inject.Singleton; @@ -32,13 +37,11 @@ import javax.inject.Singleton; /** * Logs doze events for debugging and triaging purposes. Logs are dumped in bugreports or on demand: * adb shell dumpsys activity service com.android.systemui/.SystemUIService \ - * dependency DumpController DozeLog + * dependency DumpController DozeLog,DozeStats */ @Singleton -public class DozeLog extends SysuiLog<DozeEvent> { - private static final String TAG = "DozeLog"; - - private DozeEvent mRecycledEvent; +public class DozeLog implements Dumpable { + private final DozeLogger mLogger; private boolean mPulsing; private long mSince; @@ -51,8 +54,11 @@ public class DozeLog extends SysuiLog<DozeEvent> { private SummaryStats[][] mProxStats; // [reason][near/far] @Inject - public DozeLog(KeyguardUpdateMonitor keyguardUpdateMonitor, DumpController dumpController) { - super(dumpController, TAG, MAX_DOZE_DEBUG_LOGS, MAX_DOZE_LOGS); + public DozeLog( + KeyguardUpdateMonitor keyguardUpdateMonitor, + DumpController dumpController, + DozeLogger logger) { + mLogger = logger; mSince = System.currentTimeMillis(); mPickupPulseNearVibrationStats = new SummaryStats(); mPickupPulseNotNearVibrationStats = new SummaryStats(); @@ -60,8 +66,8 @@ public class DozeLog extends SysuiLog<DozeEvent> { mScreenOnPulsingStats = new SummaryStats(); mScreenOnNotPulsingStats = new SummaryStats(); mEmergencyCallStats = new SummaryStats(); - mProxStats = new SummaryStats[DozeEvent.TOTAL_REASONS][2]; - for (int i = 0; i < DozeEvent.TOTAL_REASONS; i++) { + mProxStats = new SummaryStats[TOTAL_REASONS][2]; + for (int i = 0; i < TOTAL_REASONS; i++) { mProxStats[i][0] = new SummaryStats(); mProxStats[i][1] = new SummaryStats(); } @@ -69,42 +75,42 @@ public class DozeLog extends SysuiLog<DozeEvent> { if (keyguardUpdateMonitor != null) { keyguardUpdateMonitor.registerCallback(mKeyguardCallback); } + + dumpController.registerDumpable("DumpStats", this); } /** * Appends pickup wakeup event to the logs */ public void tracePickupWakeUp(boolean withinVibrationThreshold) { - log(DozeEvent.PICKUP_WAKEUP, "withinVibrationThreshold=" + withinVibrationThreshold); - if (mEnabled) { - (withinVibrationThreshold ? mPickupPulseNearVibrationStats - : mPickupPulseNotNearVibrationStats).append(); - } + mLogger.logPickupWakeup(withinVibrationThreshold); + (withinVibrationThreshold ? mPickupPulseNearVibrationStats + : mPickupPulseNotNearVibrationStats).append(); } /** * Appends pulse started event to the logs. * @param reason why the pulse started */ - public void tracePulseStart(@DozeEvent.Reason int reason) { - log(DozeEvent.PULSE_START, DozeEvent.reasonToString(reason)); - if (mEnabled) mPulsing = true; + public void tracePulseStart(@Reason int reason) { + mLogger.logPulseStart(reason); + mPulsing = true; } /** * Appends pulse finished event to the logs */ public void tracePulseFinish() { - log(DozeEvent.PULSE_FINISH); - if (mEnabled) mPulsing = false; + mLogger.logPulseFinish(); + mPulsing = false; } /** * Appends pulse event to the logs */ public void traceNotificationPulse() { - log(DozeEvent.NOTIFICATION_PULSE); - if (mEnabled) mNotificationPulseStats.append(); + mLogger.logNotificationPulse(); + mNotificationPulseStats.append(); } /** @@ -112,8 +118,8 @@ public class DozeLog extends SysuiLog<DozeEvent> { * @param dozing true if dozing, else false */ public void traceDozing(boolean dozing) { - log(DozeEvent.DOZING, "dozing=" + dozing); - if (mEnabled) mPulsing = false; + mLogger.logDozing(dozing); + mPulsing = false; } /** @@ -121,18 +127,15 @@ public class DozeLog extends SysuiLog<DozeEvent> { */ public void traceFling(boolean expand, boolean aboveThreshold, boolean thresholdNeeded, boolean screenOnFromTouch) { - log(DozeEvent.FLING, "expand=" + expand - + " aboveThreshold=" + aboveThreshold - + " thresholdNeeded=" + thresholdNeeded - + " screenOnFromTouch=" + screenOnFromTouch); + mLogger.logFling(expand, aboveThreshold, thresholdNeeded, screenOnFromTouch); } /** * Appends emergency call event to the logs */ public void traceEmergencyCall() { - log(DozeEvent.EMERGENCY_CALL); - if (mEnabled) mEmergencyCallStats.append(); + mLogger.logEmergencyCall(); + mEmergencyCallStats.append(); } /** @@ -140,18 +143,16 @@ public class DozeLog extends SysuiLog<DozeEvent> { * @param showing true if the keyguard bouncer is showing, else false */ public void traceKeyguardBouncerChanged(boolean showing) { - log(DozeEvent.KEYGUARD_BOUNCER_CHANGED, "showing=" + showing); + mLogger.logKeyguardBouncerChanged(showing); } /** * Appends screen-on event to the logs */ public void traceScreenOn() { - log(DozeEvent.SCREEN_ON, "pulsing=" + mPulsing); - if (mEnabled) { - (mPulsing ? mScreenOnPulsingStats : mScreenOnNotPulsingStats).append(); - mPulsing = false; - } + mLogger.logScreenOn(mPulsing); + (mPulsing ? mScreenOnPulsingStats : mScreenOnNotPulsingStats).append(); + mPulsing = false; } /** @@ -159,7 +160,7 @@ public class DozeLog extends SysuiLog<DozeEvent> { * @param why reason the screen is off */ public void traceScreenOff(int why) { - log(DozeEvent.SCREEN_OFF, "why=" + why); + mLogger.logScreenOff(why); } /** @@ -167,7 +168,7 @@ public class DozeLog extends SysuiLog<DozeEvent> { * @param delay of the missed tick */ public void traceMissedTick(String delay) { - log(DozeEvent.MISSED_TICK, "delay=" + delay); + mLogger.logMissedTick(delay); } /** @@ -176,9 +177,7 @@ public class DozeLog extends SysuiLog<DozeEvent> { * @param triggerAt time tick trigger at */ public void traceTimeTickScheduled(long when, long triggerAt) { - log(DozeEvent.TIME_TICK_SCHEDULED, - "scheduledAt=" + DATE_FORMAT.format(new Date(when)) - + " triggerAt=" + DATE_FORMAT.format(new Date(triggerAt))); + mLogger.logTimeTickScheduled(when, triggerAt); } /** @@ -186,8 +185,8 @@ public class DozeLog extends SysuiLog<DozeEvent> { * @param showing whether the keyguard is now showing */ public void traceKeyguard(boolean showing) { - log(DozeEvent.KEYGUARD_VISIBILITY_CHANGE, "showing=" + showing); - if (mEnabled && !showing) mPulsing = false; + mLogger.logKeyguardVisibilityChange(showing); + if (!showing) mPulsing = false; } /** @@ -195,7 +194,7 @@ public class DozeLog extends SysuiLog<DozeEvent> { * @param state new DozeMachine state */ public void traceState(DozeMachine.State state) { - log(DozeEvent.DOZE_STATE_CHANGED, state.name()); + mLogger.logDozeStateChanged(state); } /** @@ -203,31 +202,22 @@ public class DozeLog extends SysuiLog<DozeEvent> { * @param wake if we're waking up or sleeping. */ public void traceWakeDisplay(boolean wake) { - log(DozeEvent.WAKE_DISPLAY, "wake=" + wake); + mLogger.logWakeDisplay(wake); } /** * Appends proximity result event to the logs * @param near true if near, else false - * @param millis * @param reason why proximity result was triggered */ - public void traceProximityResult(boolean near, long millis, @DozeEvent.Reason int reason) { - log(DozeEvent.PROXIMITY_RESULT, - " reason=" + DozeEvent.reasonToString(reason) - + " near=" + near - + " millis=" + millis); - if (mEnabled) mProxStats[reason][near ? 0 : 1].append(); + public void traceProximityResult(boolean near, long millis, @Reason int reason) { + mLogger.logProximityResult(near, millis, reason); + mProxStats[reason][near ? 0 : 1].append(); } - /** - * Prints doze log timeline and consolidated stats - * @param pw - */ - public void dump(PrintWriter pw) { + @Override + public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { synchronized (DozeLog.class) { - super.dump(null, pw, null); // prints timeline - pw.print(" Doze summary stats (for "); TimeUtils.formatDuration(System.currentTimeMillis() - mSince, pw); pw.println("):"); @@ -237,32 +227,19 @@ public class DozeLog extends SysuiLog<DozeEvent> { mScreenOnPulsingStats.dump(pw, "Screen on (pulsing)"); mScreenOnNotPulsingStats.dump(pw, "Screen on (not pulsing)"); mEmergencyCallStats.dump(pw, "Emergency call"); - for (int i = 0; i < DozeEvent.TOTAL_REASONS; i++) { - final String reason = DozeEvent.reasonToString(i); + for (int i = 0; i < TOTAL_REASONS; i++) { + final String reason = reasonToString(i); mProxStats[i][0].dump(pw, "Proximity near (" + reason + ")"); mProxStats[i][1].dump(pw, "Proximity far (" + reason + ")"); } } } - private void log(@DozeEvent.EventType int eventType) { - log(eventType, ""); - } - - private void log(@DozeEvent.EventType int eventType, String msg) { - if (mRecycledEvent != null) { - mRecycledEvent = log(mRecycledEvent.init(eventType, msg)); - } else { - mRecycledEvent = log(new DozeEvent().init(eventType, msg)); - } - } - /** * Appends pulse dropped event to logs */ public void tracePulseDropped(boolean pulsePending, DozeMachine.State state, boolean blocked) { - log(DozeEvent.PULSE_DROPPED, "pulsePending=" + pulsePending + " state=" - + state.name() + " blocked=" + blocked); + mLogger.logPulseDropped(pulsePending, state, blocked); } /** @@ -270,7 +247,7 @@ public class DozeLog extends SysuiLog<DozeEvent> { * @param reason why the pulse was dropped */ public void tracePulseDropped(String reason) { - log(DozeEvent.PULSE_DROPPED, "why=" + reason); + mLogger.logPulseDropped(reason); } /** @@ -278,15 +255,15 @@ public class DozeLog extends SysuiLog<DozeEvent> { * @param disabled */ public void tracePulseTouchDisabledByProx(boolean disabled) { - log(DozeEvent.PULSE_DISABLED_BY_PROX, "disabled=" + disabled); + mLogger.logPulseTouchDisabledByProx(disabled); } /** * Appends sensor triggered event to logs * @param reason why the sensor was triggered */ - public void traceSensor(@DozeEvent.Reason int reason) { - log(DozeEvent.SENSOR_TRIGGERED, "type=" + DozeEvent.reasonToString(reason)); + public void traceSensor(@Reason int reason) { + mLogger.logSensorTriggered(reason); } private class SummaryStats { @@ -339,6 +316,42 @@ public class DozeLog extends SysuiLog<DozeEvent> { } }; - private static final int MAX_DOZE_DEBUG_LOGS = 400; - private static final int MAX_DOZE_LOGS = 50; + /** + * Converts the reason (integer) to a user-readable string + */ + public static String reasonToString(@Reason int pulseReason) { + switch (pulseReason) { + case PULSE_REASON_INTENT: return "intent"; + case PULSE_REASON_NOTIFICATION: return "notification"; + case PULSE_REASON_SENSOR_SIGMOTION: return "sigmotion"; + case REASON_SENSOR_PICKUP: return "pickup"; + case REASON_SENSOR_DOUBLE_TAP: return "doubletap"; + case PULSE_REASON_SENSOR_LONG_PRESS: return "longpress"; + case PULSE_REASON_DOCKING: return "docking"; + case PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN: return "wakelockscreen"; + case REASON_SENSOR_WAKE_UP: return "wakeup"; + case REASON_SENSOR_TAP: return "tap"; + default: throw new IllegalArgumentException("invalid reason: " + pulseReason); + } + } + + @Retention(RetentionPolicy.SOURCE) + @IntDef({PULSE_REASON_NONE, PULSE_REASON_INTENT, PULSE_REASON_NOTIFICATION, + PULSE_REASON_SENSOR_SIGMOTION, REASON_SENSOR_PICKUP, REASON_SENSOR_DOUBLE_TAP, + PULSE_REASON_SENSOR_LONG_PRESS, PULSE_REASON_DOCKING, REASON_SENSOR_WAKE_UP, + PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN, REASON_SENSOR_TAP}) + public @interface Reason {} + public static final int PULSE_REASON_NONE = -1; + public static final int PULSE_REASON_INTENT = 0; + public static final int PULSE_REASON_NOTIFICATION = 1; + public static final int PULSE_REASON_SENSOR_SIGMOTION = 2; + public static final int REASON_SENSOR_PICKUP = 3; + public static final int REASON_SENSOR_DOUBLE_TAP = 4; + public static final int PULSE_REASON_SENSOR_LONG_PRESS = 5; + public static final int PULSE_REASON_DOCKING = 6; + public static final int REASON_SENSOR_WAKE_UP = 7; + public static final int PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN = 8; + public static final int REASON_SENSOR_TAP = 9; + + public static final int TOTAL_REASONS = 10; } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt new file mode 100644 index 000000000000..42decd592071 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.doze + +import com.android.systemui.doze.DozeLog.Reason +import com.android.systemui.doze.DozeLog.reasonToString +import com.android.systemui.log.LogBuffer +import com.android.systemui.log.LogLevel.DEBUG +import com.android.systemui.log.LogLevel.ERROR +import com.android.systemui.log.LogLevel.INFO +import com.android.systemui.log.dagger.DozeLog +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale +import javax.inject.Inject + +/** Interface for logging messages to the [DozeLog]. */ +class DozeLogger @Inject constructor( + @DozeLog private val buffer: LogBuffer +) { + fun logPickupWakeup(isWithinVibrationThreshold: Boolean) { + buffer.log(TAG, DEBUG, { + bool1 = isWithinVibrationThreshold + }, { + "PickupWakeup withinVibrationThreshold=$bool1" + }) + } + + fun logPulseStart(@Reason reason: Int) { + buffer.log(TAG, INFO, { + int1 = reason + }, { + "Pulse start, reason=${reasonToString(int1)}" + }) + } + + fun logPulseFinish() { + buffer.log(TAG, INFO, {}, { "Pulse finish" }) + } + + fun logNotificationPulse() { + buffer.log(TAG, INFO, {}, { "Notification pulse" }) + } + + fun logDozing(isDozing: Boolean) { + buffer.log(TAG, INFO, { + bool1 = isDozing + }, { + "Dozing=$bool1" + }) + } + + fun logFling( + expand: Boolean, + aboveThreshold: Boolean, + thresholdNeeded: Boolean, + screenOnFromTouch: Boolean + ) { + buffer.log(TAG, DEBUG, { + bool1 = expand + bool2 = aboveThreshold + bool3 = thresholdNeeded + bool4 = screenOnFromTouch + }, { + "Fling expand=$bool1 aboveThreshold=$bool2 thresholdNeeded=$bool3 " + + "screenOnFromTouch=$bool4" + }) + } + + fun logEmergencyCall() { + buffer.log(TAG, INFO, {}, { "Emergency call" }) + } + + fun logKeyguardBouncerChanged(isShowing: Boolean) { + buffer.log(TAG, INFO, { + bool1 = isShowing + }, { + "Keyguard bouncer changed, showing=$bool1" + }) + } + + fun logScreenOn(isPulsing: Boolean) { + buffer.log(TAG, INFO, { + bool1 = isPulsing + }, { + "Screen on, pulsing=$bool1" + }) + } + + fun logScreenOff(why: Int) { + buffer.log(TAG, INFO, { + int1 = why + }, { + "Screen off, why=$int1" + }) + } + + fun logMissedTick(delay: String) { + buffer.log(TAG, ERROR, { + str1 = delay + }, { + "Missed AOD time tick by $str1" + }) + } + + fun logTimeTickScheduled(whenAt: Long, triggerAt: Long) { + buffer.log(TAG, DEBUG, { + long1 = whenAt + long2 = triggerAt + }, { + "Time tick scheduledAt=${DATE_FORMAT.format(Date(long1))} " + + "triggerAt=${DATE_FORMAT.format(Date(long2))}" + }) + } + + fun logKeyguardVisibilityChange(isShowing: Boolean) { + buffer.log(TAG, INFO, { + bool1 = isShowing + }, { + "Keyguard visibility change, isShowing=$bool1" + }) + } + + fun logDozeStateChanged(state: DozeMachine.State) { + buffer.log(TAG, INFO, { + str1 = state.name + }, { + "Doze state changed to $str1" + }) + } + + fun logWakeDisplay(isAwake: Boolean) { + buffer.log(TAG, DEBUG, { + bool1 = isAwake + }, { + "Display wakefulness changed, isAwake=$bool1" + }) + } + + fun logProximityResult(isNear: Boolean, millis: Long, @Reason reason: Int) { + buffer.log(TAG, DEBUG, { + bool1 = isNear + long1 = millis + int1 = reason + }, { + "Proximity result reason=${reasonToString(int1)} near=$bool1 millis=$long1" + }) + } + + fun logPulseDropped(pulsePending: Boolean, state: DozeMachine.State, blocked: Boolean) { + buffer.log(TAG, INFO, { + bool1 = pulsePending + str1 = state.name + bool2 = blocked + }, { + "Pulse dropped, pulsePending=$bool1 state=$str1 blocked=$bool2" + }) + } + + fun logPulseDropped(reason: String) { + buffer.log(TAG, INFO, { + str1 = reason + }, { + "Pulse dropped, why=$str1" + }) + } + + fun logPulseTouchDisabledByProx(disabled: Boolean) { + buffer.log(TAG, DEBUG, { + bool1 = disabled + }, { + "Pulse touch modified by prox, disabled=$bool1" + }) + } + + fun logSensorTriggered(@Reason reason: Int) { + buffer.log(TAG, DEBUG, { + int1 = reason + }, { + "Sensor triggered, type=${reasonToString(int1)}" + }) + } +} + +private const val TAG = "DozeLog" + +val DATE_FORMAT = SimpleDateFormat("MM-dd HH:mm:ss.S", Locale.US) diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java index 40603ab24c1e..03c25eee4f6f 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java @@ -169,7 +169,7 @@ public class DozeMachine { @MainThread public void requestState(State requestedState) { Preconditions.checkArgument(requestedState != State.DOZE_REQUEST_PULSE); - requestState(requestedState, DozeEvent.PULSE_REASON_NONE); + requestState(requestedState, DozeLog.PULSE_REASON_NONE); } @MainThread @@ -271,7 +271,7 @@ public class DozeMachine { if (newState == State.DOZE_REQUEST_PULSE) { mPulseReason = pulseReason; } else if (oldState == State.DOZE_PULSE_DONE) { - mPulseReason = DozeEvent.PULSE_REASON_NONE; + mPulseReason = DozeLog.PULSE_REASON_NONE; } } @@ -368,7 +368,7 @@ public class DozeMachine { nextState = State.DOZE; } - transitionTo(nextState, DozeEvent.PULSE_REASON_NONE); + transitionTo(nextState, DozeLog.PULSE_REASON_NONE); break; default: break; diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java index d008e665d171..44e5d3de5ca7 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java @@ -97,14 +97,14 @@ public class DozeSensors { mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION), null /* setting */, dozeParameters.getPulseOnSigMotion(), - DozeEvent.PULSE_REASON_SENSOR_SIGMOTION, false /* touchCoords */, + DozeLog.PULSE_REASON_SENSOR_SIGMOTION, false /* touchCoords */, false /* touchscreen */, dozeLog), mPickupSensor = new TriggerSensor( mSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE), Settings.Secure.DOZE_PICK_UP_GESTURE, true /* settingDef */, config.dozePickupSensorAvailable(), - DozeEvent.REASON_SENSOR_PICKUP, false /* touchCoords */, + DozeLog.REASON_SENSOR_PICKUP, false /* touchCoords */, false /* touchscreen */, false /* ignoresSetting */, dozeLog), @@ -112,7 +112,7 @@ public class DozeSensors { findSensorWithType(config.doubleTapSensorType()), Settings.Secure.DOZE_DOUBLE_TAP_GESTURE, true /* configured */, - DozeEvent.REASON_SENSOR_DOUBLE_TAP, + DozeLog.REASON_SENSOR_DOUBLE_TAP, dozeParameters.doubleTapReportsTouchCoordinates(), true /* touchscreen */, dozeLog), @@ -120,7 +120,7 @@ public class DozeSensors { findSensorWithType(config.tapSensorType()), Settings.Secure.DOZE_TAP_SCREEN_GESTURE, true /* configured */, - DozeEvent.REASON_SENSOR_TAP, + DozeLog.REASON_SENSOR_TAP, false /* reports touch coordinates */, true /* touchscreen */, dozeLog), @@ -129,7 +129,7 @@ public class DozeSensors { Settings.Secure.DOZE_PULSE_ON_LONG_PRESS, false /* settingDef */, true /* configured */, - DozeEvent.PULSE_REASON_SENSOR_LONG_PRESS, + DozeLog.PULSE_REASON_SENSOR_LONG_PRESS, true /* reports touch coordinates */, true /* touchscreen */, dozeLog), @@ -137,7 +137,7 @@ public class DozeSensors { new SensorManagerPlugin.Sensor(TYPE_WAKE_DISPLAY), Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE, mConfig.wakeScreenGestureAvailable() && alwaysOn, - DozeEvent.REASON_SENSOR_WAKE_UP, + DozeLog.REASON_SENSOR_WAKE_UP, false /* reports touch coordinates */, false /* touchscreen */, dozeLog), @@ -145,7 +145,7 @@ public class DozeSensors { new SensorManagerPlugin.Sensor(TYPE_WAKE_LOCK_SCREEN), Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE, mConfig.wakeScreenGestureAvailable(), - DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN, + DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN, false /* reports touch coordinates */, false /* touchscreen */, mConfig.getWakeLockScreenDebounce(), @@ -525,7 +525,7 @@ public class DozeSensors { /** * Called when a sensor requests a pulse - * @param pulseReason Requesting sensor, e.g. {@link DozeEvent#REASON_SENSOR_PICKUP} + * @param pulseReason Requesting sensor, e.g. {@link DozeLog#REASON_SENSOR_PICKUP} * @param screenX the location on the screen where the sensor fired or -1 * if the sensor doesn't support reporting screen locations. * @param screenY the location on the screen where the sensor fired or -1 diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index 722dc038f853..b9c056df89a1 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -127,7 +127,7 @@ public class DozeTriggers implements DozeMachine.Part { mDozeLog.tracePulseDropped("pulseOnNotificationsDisabled"); return; } - requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION, false /* performedProxCheck */, + requestPulse(DozeLog.PULSE_REASON_NOTIFICATION, false /* performedProxCheck */, onPulseSuppressedListener); mDozeLog.traceNotificationPulse(); } @@ -163,12 +163,12 @@ public class DozeTriggers implements DozeMachine.Part { @VisibleForTesting void onSensor(int pulseReason, float screenX, float screenY, float[] rawValues) { - boolean isDoubleTap = pulseReason == DozeEvent.REASON_SENSOR_DOUBLE_TAP; - boolean isTap = pulseReason == DozeEvent.REASON_SENSOR_TAP; - boolean isPickup = pulseReason == DozeEvent.REASON_SENSOR_PICKUP; - boolean isLongPress = pulseReason == DozeEvent.PULSE_REASON_SENSOR_LONG_PRESS; - boolean isWakeDisplay = pulseReason == DozeEvent.REASON_SENSOR_WAKE_UP; - boolean isWakeLockScreen = pulseReason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN; + boolean isDoubleTap = pulseReason == DozeLog.REASON_SENSOR_DOUBLE_TAP; + boolean isTap = pulseReason == DozeLog.REASON_SENSOR_TAP; + boolean isPickup = pulseReason == DozeLog.REASON_SENSOR_PICKUP; + boolean isLongPress = pulseReason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS; + boolean isWakeDisplay = pulseReason == DozeLog.REASON_SENSOR_WAKE_UP; + boolean isWakeLockScreen = pulseReason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN; boolean wakeEvent = rawValues != null && rawValues.length > 0 && rawValues[0] != 0; if (isWakeDisplay) { @@ -281,9 +281,9 @@ public class DozeTriggers implements DozeMachine.Part { // Logs AOD open due to sensor wake up. mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING) .setType(MetricsEvent.TYPE_OPEN) - .setSubtype(DozeEvent.REASON_SENSOR_WAKE_UP)); + .setSubtype(DozeLog.REASON_SENSOR_WAKE_UP)); } - }, true /* alreadyPerformedProxCheck */, DozeEvent.REASON_SENSOR_WAKE_UP); + }, true /* alreadyPerformedProxCheck */, DozeLog.REASON_SENSOR_WAKE_UP); } else { boolean paused = (state == DozeMachine.State.DOZE_AOD_PAUSED); boolean pausing = (state == DozeMachine.State.DOZE_AOD_PAUSING); @@ -292,7 +292,7 @@ public class DozeTriggers implements DozeMachine.Part { // Logs AOD close due to sensor wake up. mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING) .setType(MetricsEvent.TYPE_CLOSE) - .setSubtype(DozeEvent.REASON_SENSOR_WAKE_UP)); + .setSubtype(DozeLog.REASON_SENSOR_WAKE_UP)); } } } @@ -361,7 +361,7 @@ public class DozeTriggers implements DozeMachine.Part { // When already pulsing we're allowed to show the wallpaper directly without // requesting a new pulse. if (mMachine.getState() == DozeMachine.State.DOZE_PULSING - && reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) { + && reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) { mMachine.requestState(DozeMachine.State.DOZE_PULSING_BRIGHT); return; } @@ -426,7 +426,7 @@ public class DozeTriggers implements DozeMachine.Part { public void onReceive(Context context, Intent intent) { if (PULSE_ACTION.equals(intent.getAction())) { if (DozeMachine.DEBUG) Log.d(TAG, "Received pulse intent"); - requestPulse(DozeEvent.PULSE_REASON_INTENT, false, /* performedProxCheck */ + requestPulse(DozeLog.PULSE_REASON_INTENT, false, /* performedProxCheck */ null /* onPulseSupressedListener */); } if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(intent.getAction())) { diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java index a6aa90916c25..1c056215f1cb 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java @@ -100,7 +100,7 @@ public class DozeUi implements DozeMachine.Part { public void onPulseStarted() { try { mMachine.requestState( - reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN + reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN ? DozeMachine.State.DOZE_PULSING_BRIGHT : DozeMachine.State.DOZE_PULSING); } catch (IllegalStateException e) { diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index 80d776a59235..f33c931479ba 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -40,6 +40,7 @@ import android.content.IntentFilter; import android.content.pm.UserInfo; import android.content.res.Resources; import android.database.ContentObserver; +import android.graphics.Color; import android.graphics.drawable.Drawable; import android.media.AudioManager; import android.net.ConnectivityManager; @@ -100,7 +101,6 @@ import com.android.systemui.plugins.GlobalActions.GlobalActionsManager; import com.android.systemui.plugins.GlobalActionsPanelPlugin; import com.android.systemui.statusbar.BlurUtils; import com.android.systemui.statusbar.phone.NotificationShadeWindowController; -import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.EmergencyDialerConstants; @@ -459,12 +459,10 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mKeyguardManager.isDeviceLocked()) : null; - boolean showControls = !mKeyguardManager.isDeviceLocked() && isControlsEnabled(mContext); - ActionsDialog dialog = new ActionsDialog(mContext, mAdapter, panelViewController, mBlurUtils, mSysuiColorExtractor, mStatusBarService, mNotificationShadeWindowController, - showControls ? mControlsUiController : null); + shouldShowControls() ? mControlsUiController : null); dialog.setCanceledOnTouchOutside(false); // Handled by the custom class. dialog.setKeyguardShowing(mKeyguardShowing); @@ -538,7 +536,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, @Override public boolean shouldBeSeparated() { - return !isControlsEnabled(mContext); + return !shouldShowControls(); } @Override @@ -1135,7 +1133,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, * A single press action maintains no state, just responds to a press * and takes an action. */ - private static abstract class SinglePressAction implements Action { + + private abstract class SinglePressAction implements Action { private final int mIconResId; private final Drawable mIcon; private final int mMessageResId; @@ -1174,7 +1173,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } protected int getActionLayoutId(Context context) { - if (isControlsEnabled(context)) { + if (shouldShowControls()) { return com.android.systemui.R.layout.global_actions_grid_item_v2; } return com.android.systemui.R.layout.global_actions_grid_item; @@ -1640,8 +1639,6 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT); panelContainer.addView(mPanelController.getPanelContent(), panelParams); - mBackgroundDrawable = mPanelController.getBackgroundDrawable(); - mScrimAlpha = 1f; } } @@ -1669,7 +1666,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } if (mBackgroundDrawable == null) { mBackgroundDrawable = new ScrimDrawable(); - mScrimAlpha = ScrimController.GRADIENT_SCRIM_ALPHA; + mScrimAlpha = 0.8f; } getWindow().setBackgroundDrawable(mBackgroundDrawable); } @@ -1728,7 +1725,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, if (!(mBackgroundDrawable instanceof ScrimDrawable)) { return; } - ((ScrimDrawable) mBackgroundDrawable).setColor(colors.getMainColor(), animate); + ((ScrimDrawable) mBackgroundDrawable).setColor(Color.BLACK, animate); View decorView = getWindow().getDecorView(); if (colors.supportsDarkText()) { decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR | @@ -1900,8 +1897,10 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, return true; } - private static boolean isControlsEnabled(Context context) { - return Settings.Secure.getInt( - context.getContentResolver(), "systemui.controls_available", 0) == 1; + private boolean shouldShowControls() { + return isCurrentUserOwner() + && !mKeyguardManager.isDeviceLocked() + && Settings.Secure.getInt(mContext.getContentResolver(), + "systemui.controls_available", 0) == 1; } } diff --git a/packages/SystemUI/src/com/android/systemui/log/LogMessage.kt b/packages/SystemUI/src/com/android/systemui/log/LogMessage.kt index d971ac58fb0b..2a0a2aa6fb38 100644 --- a/packages/SystemUI/src/com/android/systemui/log/LogMessage.kt +++ b/packages/SystemUI/src/com/android/systemui/log/LogMessage.kt @@ -43,5 +43,10 @@ interface LogMessage { var int1: Int var int2: Int var long1: Long + var long2: Long var double1: Double + var bool1: Boolean + var bool2: Boolean + var bool3: Boolean + var bool4: Boolean } diff --git a/packages/SystemUI/src/com/android/systemui/log/LogMessageImpl.kt b/packages/SystemUI/src/com/android/systemui/log/LogMessageImpl.kt index 32334bc382e1..d33ac4b4a80b 100644 --- a/packages/SystemUI/src/com/android/systemui/log/LogMessageImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/log/LogMessageImpl.kt @@ -30,7 +30,12 @@ data class LogMessageImpl( override var int1: Int, override var int2: Int, override var long1: Long, - override var double1: Double + override var long2: Long, + override var double1: Double, + override var bool1: Boolean, + override var bool2: Boolean, + override var bool3: Boolean, + override var bool4: Boolean ) : LogMessage { fun reset( @@ -49,7 +54,12 @@ data class LogMessageImpl( int1 = 0 int2 = 0 long1 = 0 + long2 = 0 double1 = 0.0 + bool1 = false + bool2 = false + bool3 = false + bool4 = false } companion object Factory { @@ -65,7 +75,12 @@ data class LogMessageImpl( 0, 0, 0, - 0.0) + 0, + 0.0, + false, + false, + false, + false) } } } diff --git a/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java b/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java index 4e15668f6a34..9ee3e6765e4a 100644 --- a/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java +++ b/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java @@ -48,7 +48,7 @@ import java.util.Locale; */ public class SysuiLog<E extends Event> implements Dumpable { public static final SimpleDateFormat DATE_FORMAT = - new SimpleDateFormat("MM-dd HH:mm:ss", Locale.US); + new SimpleDateFormat("MM-dd HH:mm:ss.S", Locale.US); protected final Object mDataLock = new Object(); private final String mId; diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java index b1990beb9f57..e119beff3c6f 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java @@ -42,7 +42,7 @@ public class LogModule { @Singleton @DozeLog public static LogBuffer provideDozeLogBuffer( - LogcatEchoTrackerDebug bufferFilter, + LogcatEchoTracker bufferFilter, DumpController dumpController) { LogBuffer buffer = new LogBuffer("DozeLog", 100, 10, bufferFilter); buffer.attach(dumpController); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index 35b8312ba25c..0fd74547334b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -31,7 +31,6 @@ import android.metrics.LogMaker; import android.os.Bundle; import android.os.Handler; import android.os.Message; -import android.provider.Settings; import android.service.notification.StatusBarNotification; import android.service.quicksettings.Tile; import android.util.AttributeSet; @@ -62,7 +61,6 @@ import com.android.systemui.qs.external.CustomTile; import com.android.systemui.settings.BrightnessController; import com.android.systemui.settings.ToggleSliderView; import com.android.systemui.shared.plugins.PluginManager; -import com.android.systemui.statusbar.phone.NPVPluginManager; import com.android.systemui.statusbar.policy.BrightnessMirrorController; import com.android.systemui.statusbar.policy.BrightnessMirrorController.BrightnessMirrorListener; import com.android.systemui.tuner.TunerService; @@ -120,7 +118,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne private FrameLayout mPluginFrame; private final PluginManager mPluginManager; - private NPVPluginManager mNPVPluginManager; private final LocalMediaManager.DeviceCallback mDeviceCallback = new LocalMediaManager.DeviceCallback() { @@ -201,14 +198,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne findViewById(R.id.brightness_slider), broadcastDispatcher); mDumpController = dumpController; mPluginManager = pluginManager; - if (mPluginManager != null && Settings.System.getInt( - mContext.getContentResolver(), "npv_plugin_flag", 0) == 2) { - mPluginFrame = (FrameLayout) LayoutInflater.from(mContext).inflate( - R.layout.status_bar_expanded_plugin_frame, this, false); - addView(mPluginFrame); - mNPVPluginManager = new NPVPluginManager(mPluginFrame, mPluginManager); - } - } /** @@ -556,7 +545,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne if (mListening) { refreshAllTiles(); } - if (mNPVPluginManager != null) mNPVPluginManager.setListening(listening); } public void setListening(boolean listening, boolean expanded) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java index 557c64b7dfb9..411980b399bd 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java @@ -191,7 +191,6 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener mTile.setLabel(tile.getLabel()); mTile.setSubtitle(tile.getSubtitle()); mTile.setContentDescription(tile.getContentDescription()); - mTile.setStateDescription(tile.getStateDescription()); mTile.setState(tile.getState()); } @@ -346,12 +345,6 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener state.contentDescription = state.label; } - if (mTile.getStateDescription() != null) { - state.stateDescription = mTile.getStateDescription(); - } else { - state.stateDescription = null; - } - if (state instanceof BooleanState) { state.expandedAccessibilityClassName = Switch.class.getName(); ((BooleanState) state).value = (state.state == Tile.STATE_ACTIVE); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java index 2b53727f237e..554672d88052 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java @@ -16,7 +16,6 @@ package com.android.systemui.qs.tileimpl; import android.content.Context; import android.os.Build; -import android.provider.Settings; import android.util.Log; import android.view.ContextThemeWrapper; @@ -33,7 +32,6 @@ import com.android.systemui.qs.tiles.BluetoothTile; import com.android.systemui.qs.tiles.CastTile; import com.android.systemui.qs.tiles.CellularTile; import com.android.systemui.qs.tiles.ColorInversionTile; -import com.android.systemui.qs.tiles.ControlsTile; import com.android.systemui.qs.tiles.DataSaverTile; import com.android.systemui.qs.tiles.DndTile; import com.android.systemui.qs.tiles.FlashlightTile; @@ -60,7 +58,6 @@ public class QSFactoryImpl implements QSFactory { private final Provider<WifiTile> mWifiTileProvider; private final Provider<BluetoothTile> mBluetoothTileProvider; - private final Provider<ControlsTile> mControlsTileProvider; private final Provider<CellularTile> mCellularTileProvider; private final Provider<DndTile> mDndTileProvider; private final Provider<ColorInversionTile> mColorInversionTileProvider; @@ -85,7 +82,6 @@ public class QSFactoryImpl implements QSFactory { @Inject public QSFactoryImpl(Provider<WifiTile> wifiTileProvider, Provider<BluetoothTile> bluetoothTileProvider, - Provider<ControlsTile> controlsTileProvider, Provider<CellularTile> cellularTileProvider, Provider<DndTile> dndTileProvider, Provider<ColorInversionTile> colorInversionTileProvider, @@ -106,7 +102,6 @@ public class QSFactoryImpl implements QSFactory { Provider<ScreenRecordTile> screenRecordTileProvider) { mWifiTileProvider = wifiTileProvider; mBluetoothTileProvider = bluetoothTileProvider; - mControlsTileProvider = controlsTileProvider; mCellularTileProvider = cellularTileProvider; mDndTileProvider = dndTileProvider; mColorInversionTileProvider = colorInversionTileProvider; @@ -146,11 +141,6 @@ public class QSFactoryImpl implements QSFactory { return mWifiTileProvider.get(); case "bt": return mBluetoothTileProvider.get(); - case "controls": - if (Settings.System.getInt(mHost.getContext().getContentResolver(), - "npv_plugin_flag", 0) == 3) { - return mControlsTileProvider.get(); - } else return null; case "cell": return mCellularTileProvider.get(); case "dnd": diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java index fda9e5b1f1ef..8b7f280608a5 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java @@ -65,6 +65,7 @@ public class QSTileBaseView extends com.android.systemui.plugins.qs.QSTileView { private String mAccessibilityClass; private boolean mTileState; private boolean mCollapsedView; + private boolean mClicked; private boolean mShowRippleEffect = true; private final ImageView mBg; @@ -233,35 +234,13 @@ public class QSTileBaseView extends com.android.systemui.plugins.qs.QSTileView { setLongClickable(state.handlesLongClick); mIcon.setIcon(state, allowAnimations); setContentDescription(state.contentDescription); - final StringBuilder stateDescription = new StringBuilder(); - switch (state.state) { - case Tile.STATE_UNAVAILABLE: - stateDescription.append(mContext.getString(R.string.tile_unavailable)); - break; - case Tile.STATE_INACTIVE: - if (state instanceof QSTile.BooleanState) { - stateDescription.append(mContext.getString(R.string.switch_bar_off)); - } - break; - case Tile.STATE_ACTIVE: - if (state instanceof QSTile.BooleanState) { - stateDescription.append(mContext.getString(R.string.switch_bar_on)); - } - break; - default: - break; - } - if (!TextUtils.isEmpty(state.stateDescription)) { - stateDescription.append(", "); - stateDescription.append(state.stateDescription); - } - setStateDescription(stateDescription.toString()); mAccessibilityClass = state.state == Tile.STATE_UNAVAILABLE ? null : state.expandedAccessibilityClassName; if (state instanceof QSTile.BooleanState) { boolean newState = ((BooleanState) state).value; if (mTileState != newState) { + mClicked = false; mTileState = newState; } } @@ -318,10 +297,23 @@ public class QSTileBaseView extends com.android.systemui.plugins.qs.QSTileView { } @Override + public boolean performClick() { + mClicked = true; + return super.performClick(); + } + + @Override public void onInitializeAccessibilityEvent(AccessibilityEvent event) { super.onInitializeAccessibilityEvent(event); if (!TextUtils.isEmpty(mAccessibilityClass)) { event.setClassName(mAccessibilityClass); + if (Switch.class.getName().equals(mAccessibilityClass)) { + boolean b = mClicked ? !mTileState : mTileState; + String label = getResources() + .getString(b ? R.string.switch_bar_on : R.string.switch_bar_off); + event.setContentDescription(label); + event.setChecked(b); + } } } @@ -333,6 +325,11 @@ public class QSTileBaseView extends com.android.systemui.plugins.qs.QSTileView { if (!TextUtils.isEmpty(mAccessibilityClass)) { info.setClassName(mAccessibilityClass); if (Switch.class.getName().equals(mAccessibilityClass)) { + boolean b = mClicked ? !mTileState : mTileState; + String label = getResources() + .getString(b ? R.string.switch_bar_on : R.string.switch_bar_off); + info.setText(label); + info.setChecked(b); info.setCheckable(true); if (isLongClickable()) { info.addAction( diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java index 361b6c1b1260..9282a2e3b312 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java @@ -134,27 +134,25 @@ public class BluetoothTile extends QSTileImpl<BooleanState> { state.label = mContext.getString(R.string.quick_settings_bluetooth_label); state.secondaryLabel = TextUtils.emptyIfNull( getSecondaryLabel(enabled, connecting, connected, state.isTransient)); - state.contentDescription = state.label; - state.stateDescription = ""; if (enabled) { if (connected) { state.icon = new BluetoothConnectedTileIcon(); if (!TextUtils.isEmpty(mController.getConnectedDeviceName())) { state.label = mController.getConnectedDeviceName(); } - state.stateDescription = + state.contentDescription = mContext.getString(R.string.accessibility_bluetooth_name, state.label) + ", " + state.secondaryLabel; } else if (state.isTransient) { state.icon = ResourceIcon.get( com.android.internal.R.drawable.ic_bluetooth_transient_animation); - state.stateDescription = state.secondaryLabel; + state.contentDescription = state.secondaryLabel; } else { state.icon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_bluetooth); state.contentDescription = mContext.getString( - R.string.accessibility_quick_settings_bluetooth); - state.stateDescription = mContext.getString(R.string.accessibility_not_connected); + R.string.accessibility_quick_settings_bluetooth) + "," + + mContext.getString(R.string.accessibility_not_connected); } state.state = Tile.STATE_ACTIVE; } else { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java index 58de0575fa75..32b051e35604 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java @@ -183,7 +183,6 @@ public class CastTile extends QSTileImpl<BooleanState> { protected void handleUpdateState(BooleanState state, Object arg) { state.label = mContext.getString(R.string.quick_settings_cast_title); state.contentDescription = state.label; - state.stateDescription = ""; state.value = false; final List<CastDevice> devices = mController.getCastDevices(); boolean connecting = false; @@ -193,9 +192,8 @@ public class CastTile extends QSTileImpl<BooleanState> { if (device.state == CastDevice.STATE_CONNECTED) { state.value = true; state.secondaryLabel = getDeviceName(device); - state.stateDescription = state.stateDescription + "," - + mContext.getString( - R.string.accessibility_cast_name, state.label); + state.contentDescription = state.contentDescription + "," + + mContext.getString(R.string.accessibility_cast_name, state.label); connecting = false; break; } else if (device.state == CastDevice.STATE_CONNECTING) { @@ -219,8 +217,9 @@ public class CastTile extends QSTileImpl<BooleanState> { state.state = Tile.STATE_UNAVAILABLE; String noWifi = mContext.getString(R.string.quick_settings_cast_no_wifi); state.secondaryLabel = noWifi; + state.contentDescription = state.contentDescription + ", " + mContext.getString( + R.string.accessibility_quick_settings_not_available, noWifi); } - state.stateDescription = state.stateDescription + ", " + state.secondaryLabel; mDetailAdapter.updateItems(devices); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java index d5f86c951407..22470c7f5af5 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java @@ -194,13 +194,17 @@ public class CellularTile extends QSTileImpl<SignalState> { state.secondaryLabel = r.getString(R.string.cell_data_off); } - state.contentDescription = state.label; + + // TODO(b/77881974): Instead of switching out the description via a string check for + // we need to have two strings provided by the MobileIconGroup. + final CharSequence contentDescriptionSuffix; if (state.state == Tile.STATE_INACTIVE) { - // This information is appended later by converting the Tile.STATE_INACTIVE state. - state.stateDescription = ""; + contentDescriptionSuffix = r.getString(R.string.cell_data_off_content_description); } else { - state.stateDescription = state.secondaryLabel; + contentDescriptionSuffix = state.secondaryLabel; } + + state.contentDescription = state.label + ", " + contentDescriptionSuffix; } private CharSequence appendMobileDataType(CharSequence current, CharSequence dataType) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ControlsTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ControlsTile.java deleted file mode 100644 index 39ae66e7607a..000000000000 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ControlsTile.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.qs.tiles; - -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.FrameLayout; - -import com.android.systemui.R; -import com.android.systemui.plugins.ActivityStarter; -import com.android.systemui.plugins.NPVPlugin; -import com.android.systemui.plugins.PluginListener; -import com.android.systemui.plugins.qs.DetailAdapter; -import com.android.systemui.plugins.qs.QSTile.BooleanState; -import com.android.systemui.qs.QSHost; -import com.android.systemui.qs.tileimpl.QSTileImpl; -import com.android.systemui.shared.plugins.PluginManager; - -import javax.inject.Inject; - - -/** - * Temporary control test for prototyping - */ -public class ControlsTile extends QSTileImpl<BooleanState> { - private ControlsDetailAdapter mDetailAdapter; - private final ActivityStarter mActivityStarter; - private PluginManager mPluginManager; - private NPVPlugin mPlugin; - private Intent mHomeAppIntent; - - @Inject - public ControlsTile(QSHost host, - ActivityStarter activityStarter, - PluginManager pluginManager) { - super(host); - mActivityStarter = activityStarter; - mPluginManager = pluginManager; - mDetailAdapter = (ControlsDetailAdapter) createDetailAdapter(); - - mHomeAppIntent = new Intent(Intent.ACTION_VIEW); - mHomeAppIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - mHomeAppIntent.setComponent(new ComponentName("com.google.android.apps.chromecast.app", - "com.google.android.apps.chromecast.app.DiscoveryActivity")); - } - - @Override - public DetailAdapter getDetailAdapter() { - return mDetailAdapter; - } - - @Override - public BooleanState newTileState() { - return new BooleanState(); - } - - @Override - public void handleSetListening(boolean listening) { - - } - - @Override - public void setDetailListening(boolean listening) { - if (mPlugin == null) return; - - mPlugin.setListening(listening); - } - - @Override - protected void handleClick() { - showDetail(true); - } - - @Override - public Intent getLongClickIntent() { - return mHomeAppIntent; - } - - @Override - protected void handleSecondaryClick() { - showDetail(true); - } - - @Override - public CharSequence getTileLabel() { - return "Controls"; - } - - @Override - protected void handleUpdateState(BooleanState state, Object arg) { - state.icon = ResourceIcon.get(R.drawable.ic_lightbulb_outline_gm2_24px); - state.label = "Controls"; - } - - @Override - public boolean supportsDetailView() { - return getDetailAdapter() != null && mQSSettingsPanelOption == QSSettingsPanel.OPEN_CLICK; - } - - @Override - public int getMetricsCategory() { - return -1; - } - - @Override - protected String composeChangeAnnouncement() { - if (mState.value) { - return "On"; - } else { - return "Off"; - } - } - - @Override - public boolean isAvailable() { - return true; - } - - @Override - protected DetailAdapter createDetailAdapter() { - mDetailAdapter = new ControlsDetailAdapter(); - return mDetailAdapter; - } - - private class ControlsDetailAdapter implements DetailAdapter { - private View mDetailView; - protected FrameLayout mHomeControlsLayout; - - public CharSequence getTitle() { - return "Controls"; - } - - public Boolean getToggleState() { - return null; - } - - public boolean getToggleEnabled() { - return false; - } - - public View createDetailView(Context context, View convertView, final ViewGroup parent) { - if (convertView != null) return convertView; - - mHomeControlsLayout = (FrameLayout) LayoutInflater.from(context).inflate( - R.layout.home_controls, parent, false); - mHomeControlsLayout.setVisibility(View.VISIBLE); - parent.addView(mHomeControlsLayout); - - mPluginManager.addPluginListener( - new PluginListener<NPVPlugin>() { - @Override - public void onPluginConnected(NPVPlugin plugin, - Context pluginContext) { - mPlugin = plugin; - mPlugin.attachToRoot(mHomeControlsLayout); - mPlugin.setListening(true); - } - - @Override - public void onPluginDisconnected(NPVPlugin plugin) { - mPlugin.setListening(false); - mHomeControlsLayout.removeAllViews(); - - } - }, NPVPlugin.class, false); - return mHomeControlsLayout; - } - - public Intent getSettingsIntent() { - return mHomeAppIntent; - } - - public void setToggleState(boolean state) { - - } - - public int getMetricsCategory() { - return -1; - } - - public boolean hasHeader() { - return false; - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java index 9215da4cda9a..52d1a5b3b991 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java @@ -240,8 +240,6 @@ public class DndTile extends QSTileImpl<BooleanState> { zen != Global.ZEN_MODE_OFF, mController.getConfig(), false)); state.icon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_dnd); checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_ADJUST_VOLUME); - // Keeping the secondaryLabel in contentDescription instead of stateDescription is easier - // to understand. switch (zen) { case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: state.contentDescription = diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java index 792c36477962..dafdd89ee62c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java @@ -102,13 +102,14 @@ public class FlashlightTile extends QSTileImpl<BooleanState> implements } state.label = mHost.getContext().getString(R.string.quick_settings_flashlight_label); state.secondaryLabel = ""; - state.stateDescription = ""; if (!mFlashlightController.isAvailable()) { state.icon = mIcon; state.slash.isSlashed = true; state.secondaryLabel = mContext.getString( R.string.quick_settings_flashlight_camera_in_use); - state.stateDescription = state.secondaryLabel; + state.contentDescription = mContext.getString( + R.string.accessibility_quick_settings_flashlight_unavailable) + + ", " + state.secondaryLabel; state.state = Tile.STATE_UNAVAILABLE; return; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java index fd6b936d71c0..001e09406e3a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java @@ -147,7 +147,6 @@ public class HotspotTile extends QSTileImpl<BooleanState> { state.secondaryLabel = getSecondaryLabel( isTileActive, isTransient, isDataSaverEnabled, numConnectedDevices); - state.stateDescription = state.secondaryLabel; } @Nullable diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java index e617867eb10e..fbdca3ba1c7b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java @@ -105,8 +105,15 @@ public class LocationTile extends QSTileImpl<BooleanState> { } state.icon = mIcon; state.slash.isSlashed = !state.value; - state.label = mContext.getString(R.string.quick_settings_location_label); - state.contentDescription = state.label; + if (locationEnabled) { + state.label = mContext.getString(R.string.quick_settings_location_label); + state.contentDescription = mContext.getString( + R.string.accessibility_quick_settings_location_on); + } else { + state.label = mContext.getString(R.string.quick_settings_location_label); + state.contentDescription = mContext.getString( + R.string.accessibility_quick_settings_location_off); + } state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE; state.expandedAccessibilityClassName = Switch.class.getName(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java index 6e8dcf36bacc..b7ce101cacab 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java @@ -195,7 +195,6 @@ public class WifiTile extends QSTileImpl<SignalState> { state.activityIn = cb.enabled && cb.activityIn; state.activityOut = cb.enabled && cb.activityOut; final StringBuffer minimalContentDescription = new StringBuffer(); - final StringBuffer minimalStateDescription = new StringBuffer(); final Resources r = mContext.getResources(); if (isTransient) { state.icon = ResourceIcon.get( @@ -220,14 +219,13 @@ public class WifiTile extends QSTileImpl<SignalState> { mContext.getString(R.string.quick_settings_wifi_label)).append(","); if (state.value) { if (wifiConnected) { - minimalStateDescription.append(cb.wifiSignalContentDescription); + minimalContentDescription.append(cb.wifiSignalContentDescription).append(","); minimalContentDescription.append(removeDoubleQuotes(cb.ssid)); if (!TextUtils.isEmpty(state.secondaryLabel)) { minimalContentDescription.append(",").append(state.secondaryLabel); } } } - state.stateDescription = minimalStateDescription.toString(); state.contentDescription = minimalContentDescription.toString(); state.dualLabelContentDescription = r.getString( R.string.accessibility_quick_settings_open_settings, getTileLabel()); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java index e54ee51fb9d4..7853dc388bcb 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java @@ -103,11 +103,14 @@ public class WorkModeTile extends QSTileImpl<BooleanState> implements state.icon = mIcon; if (state.value) { state.slash.isSlashed = false; + state.contentDescription = mContext.getString( + R.string.accessibility_quick_settings_work_mode_on); } else { state.slash.isSlashed = true; + state.contentDescription = mContext.getString( + R.string.accessibility_quick_settings_work_mode_off); } state.label = mContext.getString(R.string.quick_settings_work_mode_label); - state.contentDescription = state.label; state.expandedAccessibilityClassName = Switch.class.getName(); state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java index afaa593b3bb9..e7d6eba1dcb3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java @@ -22,7 +22,6 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.Dependency; -import com.android.systemui.doze.DozeEvent; import com.android.systemui.doze.DozeHost; import com.android.systemui.doze.DozeLog; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -53,7 +52,7 @@ public class DozeScrimController implements StateListener { public void onDisplayBlanked() { if (DEBUG) { Log.d(TAG, "Pulse in, mDozing=" + mDozing + " mPulseReason=" - + DozeEvent.reasonToString(mPulseReason)); + + DozeLog.reasonToString(mPulseReason)); } if (!mDozing) { return; @@ -74,8 +73,8 @@ public class DozeScrimController implements StateListener { // Notifications should time out on their own. Pulses due to notifications should // instead be managed externally based off the notification's lifetime. // Dock also controls the time out by self. - if (mPulseReason != DozeEvent.PULSE_REASON_NOTIFICATION - && mPulseReason != DozeEvent.PULSE_REASON_DOCKING) { + if (mPulseReason != DozeLog.PULSE_REASON_NOTIFICATION + && mPulseReason != DozeLog.PULSE_REASON_DOCKING) { mHandler.postDelayed(mPulseOut, mDozeParameters.getPulseVisibleDuration()); mHandler.postDelayed(mPulseOutExtended, mDozeParameters.getPulseVisibleDurationExtended()); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java index 04efc2d7558d..56e5cb08f6d1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java @@ -31,7 +31,6 @@ import android.view.View; import com.android.internal.annotations.VisibleForTesting; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.assist.AssistManager; -import com.android.systemui.doze.DozeEvent; import com.android.systemui.doze.DozeHost; import com.android.systemui.doze.DozeLog; import com.android.systemui.doze.DozeReceiver; @@ -221,18 +220,18 @@ public final class DozeServiceHost implements DozeHost { @Override public void pulseWhileDozing(@NonNull PulseCallback callback, int reason) { - if (reason == DozeEvent.PULSE_REASON_SENSOR_LONG_PRESS) { + if (reason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS) { mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE, "com.android.systemui:LONG_PRESS"); mAssistManagerLazy.get().startAssist(new Bundle()); return; } - if (reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) { + if (reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) { mScrimController.setWakeLockScreenSensorActive(true); } - boolean passiveAuthInterrupt = reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN + boolean passiveAuthInterrupt = reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN && mWakeLockScreenPerformsAuth; // Set the state to pulsing, so ScrimController will know what to do once we ask it to // execute the transition. The pulse callback will then be invoked when the scrims @@ -332,7 +331,7 @@ public final class DozeServiceHost implements DozeHost { @Override public void extendPulse(int reason) { - if (reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) { + if (reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) { mScrimController.setWakeLockScreenSensorActive(true); } if (mDozeScrimController.isPulsing() && mHeadsUpManagerPhone.hasNotifications()) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NPVPluginManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NPVPluginManager.kt deleted file mode 100644 index 53601babfd56..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NPVPluginManager.kt +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.phone - -import android.content.Context -import android.view.View -import android.view.ViewGroup.MarginLayoutParams -import android.widget.FrameLayout -import com.android.systemui.plugins.NPVPlugin -import com.android.systemui.plugins.PluginListener -import com.android.systemui.qs.TouchAnimator -import com.android.systemui.shared.plugins.PluginManager - -/** - * Manages the NPVPlugin view and state - * - * Abstracts NPVPlugin from NPV and helps animate on expansion and respond to changes in Config. - */ -class NPVPluginManager( - var parent: FrameLayout, - val pluginManager: PluginManager -) : PluginListener<NPVPlugin> { - - private var plugin: NPVPlugin? = null - private var animator = createAnimator() - private var yOffset = 0f - - private fun createAnimator() = TouchAnimator.Builder() - .addFloat(parent, "alpha", 1f, 0f) - .addFloat(parent, "scaleY", 1f, 0f) - .build() - - init { - pluginManager.addPluginListener(NPVPlugin.ACTION, this, NPVPlugin::class.java, false) - parent.pivotY = 0f - } - - override fun onPluginConnected(plugin: NPVPlugin, pluginContext: Context) { - parent.removeAllViews() - plugin.attachToRoot(parent) - this.plugin = plugin - parent.visibility = View.VISIBLE - } - - fun changeVisibility(visibility: Int) { - parent.visibility = if (plugin != null) visibility else View.GONE - } - - fun destroy() { - plugin?.onDestroy() - pluginManager.removePluginListener(this) - } - - override fun onPluginDisconnected(plugin: NPVPlugin) { - if (this.plugin == plugin) { - this.plugin = null - parent.removeAllViews() - parent.visibility = View.GONE - } - } - - fun setListening(listening: Boolean) { - plugin?.setListening(listening) - } - - fun setExpansion(expansion: Float, headerTranslation: Float, heightDiff: Float) { - parent.setTranslationY(expansion * heightDiff + headerTranslation + yOffset) - if (!expansion.isNaN()) animator.setPosition(expansion) - } - - fun replaceFrameLayout(newParent: FrameLayout) { - newParent.visibility = parent.visibility - parent.removeAllViews() - plugin?.attachToRoot(newParent) - parent = newParent - animator = createAnimator() - } - - fun getHeight() = - if (plugin != null) { - parent.height + (parent.getLayoutParams() as MarginLayoutParams).topMargin - } else 0 - - fun setYOffset(y: Float) { - yOffset = y - parent.setTranslationY(yOffset) - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index 6112ae88f634..d2186f959aba 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -25,10 +25,8 @@ import android.animation.ValueAnimator; import android.app.ActivityManager; import android.app.Fragment; import android.app.StatusBarManager; -import android.content.Context; import android.content.pm.ResolveInfo; import android.content.res.Configuration; -import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; @@ -40,8 +38,6 @@ import android.graphics.drawable.Drawable; import android.hardware.biometrics.BiometricSourceType; import android.os.PowerManager; import android.os.SystemClock; -import android.provider.DeviceConfig; -import android.provider.Settings; import android.util.Log; import android.util.MathUtils; import android.view.LayoutInflater; @@ -57,7 +53,6 @@ import android.widget.FrameLayout; import android.widget.TextView; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.LatencyTracker; @@ -73,13 +68,10 @@ import com.android.systemui.doze.DozeLog; import com.android.systemui.fragments.FragmentHostManager; import com.android.systemui.fragments.FragmentHostManager.FragmentListener; import com.android.systemui.plugins.FalsingManager; -import com.android.systemui.plugins.HomeControlsPlugin; -import com.android.systemui.plugins.PluginListener; import com.android.systemui.plugins.qs.QS; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.qs.QSFragment; -import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.FlingAnimationUtils; import com.android.systemui.statusbar.GestureRecorder; @@ -113,7 +105,6 @@ import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.util.InjectionInflationController; -import com.android.systemui.util.Utils; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -173,8 +164,6 @@ public class NotificationPanelViewController extends PanelViewController { private final ConfigurationController mConfigurationController; private final FlingAnimationUtils.Builder mFlingAnimationUtilsBuilder; - private double mQqsSplitFraction; - // Cap and total height of Roboto font. Needs to be adjusted when font for the big clock is // changed. private static final int CAP_HEIGHT = 1456; @@ -258,7 +247,6 @@ public class NotificationPanelViewController extends PanelViewController { private View mQsNavbarScrim; private NotificationsQuickSettingsContainer mNotificationContainerParent; private NotificationStackScrollLayout mNotificationStackScroller; - private FrameLayout mHomeControlsLayout; private boolean mAnimateNextPositionUpdate; private int mTrackingPointer; @@ -446,9 +434,6 @@ public class NotificationPanelViewController extends PanelViewController { */ private boolean mDelayShowingKeyguardStatusBar; - private PluginManager mPluginManager; - private FrameLayout mPluginFrame; - private NPVPluginManager mNPVPluginManager; private int mOldLayoutDirection; @Inject @@ -457,7 +442,7 @@ public class NotificationPanelViewController extends PanelViewController { NotificationWakeUpCoordinator coordinator, PulseExpansionHandler pulseExpansionHandler, DynamicPrivacyController dynamicPrivacyController, KeyguardBypassController bypassController, FalsingManager falsingManager, - PluginManager pluginManager, ShadeController shadeController, + ShadeController shadeController, NotificationLockscreenUserManager notificationLockscreenUserManager, NotificationEntryManager notificationEntryManager, KeyguardStateController keyguardStateController, @@ -523,7 +508,6 @@ public class NotificationPanelViewController extends PanelViewController { }); mBottomAreaShadeAlphaAnimator.setDuration(160); mBottomAreaShadeAlphaAnimator.setInterpolator(Interpolators.ALPHA_OUT); - mPluginManager = pluginManager; mShadeController = shadeController; mLockscreenUserManager = notificationLockscreenUserManager; mEntryManager = notificationEntryManager; @@ -553,7 +537,6 @@ public class NotificationPanelViewController extends PanelViewController { mBigClockContainer = mView.findViewById(R.id.big_clock_container); keyguardClockSwitch.setBigClockContainer(mBigClockContainer); - mHomeControlsLayout = mView.findViewById(R.id.home_controls_layout); mNotificationContainerParent = mView.findViewById(R.id.notification_container_parent); mNotificationStackScroller = mView.findViewById(R.id.notification_stack_scroller); mNotificationStackScroller.setOnHeightChangedListener(mOnHeightChangedListener); @@ -563,12 +546,6 @@ public class NotificationPanelViewController extends PanelViewController { mKeyguardBottomArea = mView.findViewById(R.id.keyguard_bottom_area); mQsNavbarScrim = mView.findViewById(R.id.qs_navbar_scrim); mLastOrientation = mResources.getConfiguration().orientation; - mPluginFrame = mView.findViewById(R.id.plugin_frame); - if (Settings.System.getInt(mView.getContext().getContentResolver(), "npv_plugin_flag", 0) - == 1) { - mNPVPluginManager = new NPVPluginManager(mPluginFrame, mPluginManager); - } - initBottomArea(); @@ -592,19 +569,6 @@ public class NotificationPanelViewController extends PanelViewController { } }); - mPluginManager.addPluginListener(new PluginListener<HomeControlsPlugin>() { - - @Override - public void onPluginConnected(HomeControlsPlugin plugin, Context pluginContext) { - plugin.sendParentGroup(mHomeControlsLayout); - } - - @Override - public void onPluginDisconnected(HomeControlsPlugin plugin) { - - } - }, HomeControlsPlugin.class, false); - mView.setRtlChangeListener(layoutDirection -> { if (layoutDirection != mOldLayoutDirection) { mAffordanceHelper.onRtlPropertiesChanged(); @@ -637,9 +601,6 @@ public class NotificationPanelViewController extends PanelViewController { com.android.internal.R.dimen.status_bar_height); mHeadsUpInset = statusbarHeight + mResources.getDimensionPixelSize( R.dimen.heads_up_status_bar_padding); - mQqsSplitFraction = ((float) mResources.getInteger(R.integer.qqs_split_fraction)) / ( - mResources.getInteger(R.integer.qqs_split_fraction) + mResources.getInteger( - R.integer.qs_split_fraction)); } /** @@ -679,18 +640,6 @@ public class NotificationPanelViewController extends PanelViewController { lp.gravity = panelGravity; mNotificationStackScroller.setLayoutParams(lp); } - int sideMargin = mResources.getDimensionPixelOffset(R.dimen.notification_side_paddings); - int topMargin = sideMargin; - lp = (FrameLayout.LayoutParams) mPluginFrame.getLayoutParams(); - if (lp.width != qsWidth || lp.gravity != panelGravity || lp.leftMargin != sideMargin - || lp.rightMargin != sideMargin || lp.topMargin != topMargin) { - lp.width = qsWidth; - lp.gravity = panelGravity; - lp.leftMargin = sideMargin; - lp.rightMargin = sideMargin; - lp.topMargin = topMargin; - mPluginFrame.setLayoutParams(lp); - } } private void reInflateViews() { @@ -732,41 +681,6 @@ public class NotificationPanelViewController extends PanelViewController { if (mOnReinflationListener != null) { mOnReinflationListener.run(); } - reinflatePluginContainer(); - } - - private void reinflatePluginContainer() { - int index = mView.indexOfChild(mPluginFrame); - mView.removeView(mPluginFrame); - mPluginFrame = (FrameLayout) mInjectionInflationController.injectable( - LayoutInflater.from(mView.getContext())).inflate( - R.layout.status_bar_expanded_plugin_frame, mView, false); - mView.addView(mPluginFrame, index); - - Resources res = mView.getResources(); - int qsWidth = res.getDimensionPixelSize(R.dimen.qs_panel_width); - int panelGravity = mView.getResources().getInteger( - R.integer.notification_panel_layout_gravity); - FrameLayout.LayoutParams lp; - int sideMargin = res.getDimensionPixelOffset(R.dimen.notification_side_paddings); - int topMargin = res.getDimensionPixelOffset( - com.android.internal.R.dimen.quick_qs_total_height); - if (Utils.useQsMediaPlayer(mView.getContext())) { - topMargin = res.getDimensionPixelOffset( - com.android.internal.R.dimen.quick_qs_total_height_with_media); - } - lp = (FrameLayout.LayoutParams) mPluginFrame.getLayoutParams(); - if (lp.width != qsWidth || lp.gravity != panelGravity || lp.leftMargin != sideMargin - || lp.rightMargin != sideMargin || lp.topMargin != topMargin) { - lp.width = qsWidth; - lp.gravity = panelGravity; - lp.leftMargin = sideMargin; - lp.rightMargin = sideMargin; - lp.topMargin = topMargin; - mPluginFrame.setLayoutParams(lp); - } - - if (mNPVPluginManager != null) mNPVPluginManager.replaceFrameLayout(mPluginFrame); } private void initBottomArea() { @@ -1266,17 +1180,6 @@ public class NotificationPanelViewController extends PanelViewController { // earlier so the state is already up to date when dragging down. setListening(true); } - if (isQsSplitEnabled() && !mKeyguardShowing) { - if (mQsExpandImmediate) { - mNotificationStackScroller.setVisibility(View.GONE); - mQsFrame.setVisibility(View.VISIBLE); - mHomeControlsLayout.setVisibility(View.VISIBLE); - } else { - mNotificationStackScroller.setVisibility(View.VISIBLE); - mQsFrame.setVisibility(View.GONE); - mHomeControlsLayout.setVisibility(View.GONE); - } - } return false; } @@ -1286,17 +1189,6 @@ public class NotificationPanelViewController extends PanelViewController { || y <= mQs.getView().getY() + mQs.getView().getHeight()); } - private boolean isOnQsEndArea(float x) { - if (!isQsSplitEnabled()) return false; - if (mView.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR) { - return x >= mQsFrame.getX() + mQqsSplitFraction * mQsFrame.getWidth() - && x <= mQsFrame.getX() + mQsFrame.getWidth(); - } else { - return x >= mQsFrame.getX() - && x <= mQsFrame.getX() + (1 - mQqsSplitFraction) * mQsFrame.getWidth(); - } - } - private boolean isOpenQsEvent(MotionEvent event) { final int pointerCount = event.getPointerCount(); final int action = event.getActionMasked(); @@ -1317,9 +1209,7 @@ public class NotificationPanelViewController extends PanelViewController { MotionEvent.BUTTON_SECONDARY) || event.isButtonPressed( MotionEvent.BUTTON_TERTIARY)); - final boolean onHeaderRight = isOnQsEndArea(event.getX()); - - return twoFingerDrag || stylusButtonClickDrag || mouseButtonClickDrag || onHeaderRight; + return twoFingerDrag || stylusButtonClickDrag || mouseButtonClickDrag; } private void handleQsDown(MotionEvent event) { @@ -1659,10 +1549,7 @@ public class NotificationPanelViewController extends PanelViewController { mBarState != StatusBarState.KEYGUARD && (!mQsExpanded || mQsExpansionFromOverscroll)); updateEmptyShadeView(); - if (mNPVPluginManager != null) { - mNPVPluginManager.changeVisibility( - (mBarState != StatusBarState.KEYGUARD) ? View.VISIBLE : View.INVISIBLE); - } + mQsNavbarScrim.setVisibility( mBarState == StatusBarState.SHADE && mQsExpanded && !mStackScrollerOverscrolling && mQsScrimEnabled ? View.VISIBLE : View.INVISIBLE); @@ -1718,9 +1605,6 @@ public class NotificationPanelViewController extends PanelViewController { float qsExpansionFraction = getQsExpansionFraction(); mQs.setQsExpansion(qsExpansionFraction, getHeaderTranslation()); int heightDiff = mQs.getDesiredHeight() - mQs.getQsMinExpansionHeight(); - if (mNPVPluginManager != null) { - mNPVPluginManager.setExpansion(qsExpansionFraction, getHeaderTranslation(), heightDiff); - } mNotificationStackScroller.setQsExpansionFraction(qsExpansionFraction); } @@ -2015,7 +1899,6 @@ public class NotificationPanelViewController extends PanelViewController { targetHeight = mQsMinExpansionHeight + t * (mQsMaxExpansionHeight - mQsMinExpansionHeight); setQsExpansion(targetHeight); - mHomeControlsLayout.setTranslationY(targetHeight); } updateExpandedHeight(expandedHeight); updateHeader(); @@ -2150,7 +2033,6 @@ public class NotificationPanelViewController extends PanelViewController { appearAmount = mNotificationStackScroller.calculateAppearFractionBypass(); } startHeight = -mQs.getQsMinExpansionHeight(); - if (mNPVPluginManager != null) startHeight -= mNPVPluginManager.getHeight(); } float translation = MathUtils.lerp(startHeight, 0, Math.min(1.0f, appearAmount)) + mExpandOffset; @@ -2294,7 +2176,6 @@ public class NotificationPanelViewController extends PanelViewController { mKeyguardStatusBar.setListening(listening); if (mQs == null) return; mQs.setListening(listening); - if (mNPVPluginManager != null) mNPVPluginManager.setListening(listening); } @Override @@ -3029,11 +2910,6 @@ public class NotificationPanelViewController extends PanelViewController { mOnReinflationListener = onReinflationListener; } - public static boolean isQsSplitEnabled() { - return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, - SystemUiDeviceConfigFlags.QS_SPLIT_ENABLED, false); - } - public void setAlpha(float alpha) { mView.setAlpha(alpha); } @@ -3500,9 +3376,7 @@ public class NotificationPanelViewController extends PanelViewController { } @Override - public void onUiModeChanged() { - reinflatePluginContainer(); - } + public void onUiModeChanged() {} } private class StatusBarStateListener implements StateListener { @@ -3517,11 +3391,6 @@ public class NotificationPanelViewController extends PanelViewController { mBarState = statusBarState; mKeyguardShowing = keyguardShowing; - if (mKeyguardShowing && isQsSplitEnabled()) { - mNotificationStackScroller.setVisibility(View.VISIBLE); - mQsFrame.setVisibility(View.VISIBLE); - mHomeControlsLayout.setVisibility(View.GONE); - } if (oldState == StatusBarState.KEYGUARD && (goingToFullShade || statusBarState == StatusBarState.SHADE_LOCKED)) { @@ -3544,7 +3413,6 @@ public class NotificationPanelViewController extends PanelViewController { } else { mKeyguardStatusBar.setAlpha(1f); mKeyguardStatusBar.setVisibility(keyguardShowing ? View.VISIBLE : View.INVISIBLE); - ((PhoneStatusBarView) mBar).maybeShowDivider(keyguardShowing); if (keyguardShowing && oldState != mBarState) { if (mQs != null) { mQs.hideImmediately(); @@ -3622,10 +3490,6 @@ public class NotificationPanelViewController extends PanelViewController { int oldMaxHeight = mQsMaxExpansionHeight; if (mQs != null) { mQsMinExpansionHeight = mKeyguardShowing ? 0 : mQs.getQsMinExpansionHeight(); - if (mNPVPluginManager != null) { - mNPVPluginManager.setYOffset(mQsMinExpansionHeight); - mQsMinExpansionHeight += mNPVPluginManager.getHeight(); - } mQsMaxExpansionHeight = mQs.getDesiredHeight(); mNotificationStackScroller.setMaxTopPadding( mQsMaxExpansionHeight + mQsNotificationTopPadding); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java index 3af80387778b..10b68b9a518d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java @@ -16,8 +16,10 @@ package com.android.systemui.statusbar.phone; +import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_BEHAVIOR_CONTROLLED; import static com.android.systemui.DejankUtils.whitelistIpcs; import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT; @@ -180,6 +182,13 @@ public class NotificationShadeWindowController implements Callback, Dumpable, mLp.setTitle("NotificationShade"); mLp.packageName = mContext.getPackageName(); mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; + + // We use BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE here, however, there is special logic in + // window manager which disables the transient show behavior. + // TODO: Clean this up once that behavior moves into the Shell. + mLp.privateFlags |= PRIVATE_FLAG_BEHAVIOR_CONTROLLED; + mLp.insetsFlags.behavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; + mWindowManager.addView(mNotificationShadeView, mLp); mLpChanged.copyFrom(mLp); onThemeChanged(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java index 96b4b22d0580..e8bc2f58adb4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java @@ -32,7 +32,7 @@ public final class PhoneStatusBarTransitions extends BarTransitions { private final PhoneStatusBarView mView; private final float mIconAlphaWhenOpaque; - private View mLeftSide, mStatusIcons, mBattery, mClock, mDivider; + private View mLeftSide, mStatusIcons, mBattery, mClock; private Animator mCurrentAnimation; public PhoneStatusBarTransitions(PhoneStatusBarView view) { @@ -46,7 +46,6 @@ public final class PhoneStatusBarTransitions extends BarTransitions { mLeftSide = mView.findViewById(R.id.status_bar_left_side); mStatusIcons = mView.findViewById(R.id.statusIcons); mBattery = mView.findViewById(R.id.battery); - mDivider = mView.findViewById(R.id.divider); applyModeBackground(-1, getMode(), false /*animate*/); applyMode(getMode(), false /*animate*/); } @@ -89,7 +88,6 @@ public final class PhoneStatusBarTransitions extends BarTransitions { anims.playTogether( animateTransitionTo(mLeftSide, newAlpha), animateTransitionTo(mStatusIcons, newAlpha), - animateTransitionTo(mDivider, newAlpha), animateTransitionTo(mBattery, newAlphaBC) ); if (isLightsOut(mode)) { @@ -100,8 +98,7 @@ public final class PhoneStatusBarTransitions extends BarTransitions { } else { mLeftSide.setAlpha(newAlpha); mStatusIcons.setAlpha(newAlpha); - mDivider.setAlpha(newAlpha); mBattery.setAlpha(newAlphaBC); } } -}
\ No newline at end of file +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java index ffbbffc0d8d9..f3b0a79f9518 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java @@ -25,7 +25,6 @@ import android.content.Context; import android.content.res.Configuration; import android.graphics.Point; import android.graphics.Rect; -import android.provider.DeviceConfig; import android.util.AttributeSet; import android.util.EventLog; import android.util.Pair; @@ -40,8 +39,6 @@ import android.view.accessibility.AccessibilityEvent; import android.widget.FrameLayout; import android.widget.LinearLayout; -import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; -import com.android.systemui.DarkReceiverImpl; import com.android.systemui.Dependency; import com.android.systemui.EventLogTags; import com.android.systemui.R; @@ -81,9 +78,6 @@ public class PhoneStatusBarView extends PanelBar { @Nullable private DisplayCutout mDisplayCutout; - private DarkReceiverImpl mSplitDivider; - private View mDividerContainer; - private QsSplitPropertyListener mPropertyListener; /** * Draw this many pixels into the left/right side of the cutout to optimally use the space */ @@ -115,10 +109,6 @@ public class PhoneStatusBarView extends PanelBar { mBattery = findViewById(R.id.battery); mCutoutSpace = findViewById(R.id.cutout_space_view); mCenterIconSpace = findViewById(R.id.centered_icon_area); - mSplitDivider = findViewById(R.id.divider); - mDividerContainer = findViewById(R.id.divider_container); - maybeShowDivider(true); - mPropertyListener = new QsSplitPropertyListener(mDividerContainer); updateResources(); } @@ -128,26 +118,16 @@ public class PhoneStatusBarView extends PanelBar { super.onAttachedToWindow(); // Always have Battery meters in the status bar observe the dark/light modes. Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mBattery); - Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mSplitDivider); - maybeShowDivider(true); if (updateOrientationAndCutout(getResources().getConfiguration().orientation)) { updateLayoutForCutout(); } - if (mPropertyListener != null) { - DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, - mContext.getMainExecutor(), mPropertyListener); - } } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); Dependency.get(DarkIconDispatcher.class).removeDarkReceiver(mBattery); - Dependency.get(DarkIconDispatcher.class).removeDarkReceiver(mSplitDivider); mDisplayCutout = null; - if (mPropertyListener != null) { - DeviceConfig.removeOnPropertiesChangedListener(mPropertyListener); - } } @Override @@ -216,7 +196,6 @@ public class PhoneStatusBarView extends PanelBar { public void onPanelPeeked() { super.onPanelPeeked(); mBar.makeExpandedVisible(false); - maybeShowDivider(!mBar.mPanelExpanded); } @Override @@ -225,7 +204,6 @@ public class PhoneStatusBarView extends PanelBar { // Close the status bar in the next frame so we can show the end of the animation. post(mHideExpandedRunnable); mIsFullyOpenedPanel = false; - maybeShowDivider(!mBar.mPanelExpanded); } public void removePendingHideExpandedRunnables() { @@ -239,7 +217,6 @@ public class PhoneStatusBarView extends PanelBar { mPanel.getView().sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); } mIsFullyOpenedPanel = true; - maybeShowDivider(!mBar.mPanelExpanded); } @Override @@ -263,28 +240,24 @@ public class PhoneStatusBarView extends PanelBar { mBar.onTrackingStarted(); mScrimController.onTrackingStarted(); removePendingHideExpandedRunnables(); - maybeShowDivider(!mBar.mPanelExpanded); } @Override public void onClosingFinished() { super.onClosingFinished(); mBar.onClosingFinished(); - maybeShowDivider(!mBar.mPanelExpanded); } @Override public void onTrackingStopped(boolean expand) { super.onTrackingStopped(expand); mBar.onTrackingStopped(expand); - maybeShowDivider(!mBar.mPanelExpanded); } @Override public void onExpandingFinished() { super.onExpandingFinished(); mScrimController.onExpandingFinished(); - maybeShowDivider(!mBar.mPanelExpanded); } @Override @@ -416,31 +389,4 @@ public class PhoneStatusBarView extends PanelBar { protected boolean shouldPanelBeVisible() { return mHeadsUpVisible || super.shouldPanelBeVisible(); } - - void maybeShowDivider(boolean showDivider) { - int state = - showDivider && NotificationPanelViewController.isQsSplitEnabled() - ? View.VISIBLE : View.GONE; - mDividerContainer.setVisibility(state); - } - - private static class QsSplitPropertyListener implements - DeviceConfig.OnPropertiesChangedListener { - private final View mDivider; - - QsSplitPropertyListener(View divider) { - mDivider = divider; - } - - @Override - public void onPropertiesChanged(DeviceConfig.Properties properties) { - if (properties.getNamespace().equals(DeviceConfig.NAMESPACE_SYSTEMUI) - && properties.getKeyset().contains( - SystemUiDeviceConfigFlags.QS_SPLIT_ENABLED)) { - boolean splitEnabled = properties.getBoolean( - SystemUiDeviceConfigFlags.QS_SPLIT_ENABLED, false); - mDivider.setVisibility(splitEnabled ? VISIBLE : GONE); - } - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 86a81ce3d1f1..6a046884e835 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -16,6 +16,9 @@ package com.android.systemui.statusbar.phone; +import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL; +import static android.view.ViewRootImpl.sNewInsetsMode; +import static android.view.WindowInsets.Type.navigationBars; import static com.android.systemui.plugins.ActivityStarter.OnDismissAction; import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_UNLOCK_FADING; import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK; @@ -789,7 +792,12 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb private Runnable mMakeNavigationBarVisibleRunnable = new Runnable() { @Override public void run() { - mStatusBar.getNavigationBarView().getRootView().setVisibility(View.VISIBLE); + if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) { + mStatusBar.getNotificationShadeWindowView().getWindowInsetsController() + .show(navigationBars()); + } else { + mStatusBar.getNavigationBarView().getRootView().setVisibility(View.VISIBLE); + } } }; @@ -856,7 +864,12 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb } } else { mContainer.removeCallbacks(mMakeNavigationBarVisibleRunnable); - mStatusBar.getNavigationBarView().getRootView().setVisibility(View.GONE); + if (sNewInsetsMode == NEW_INSETS_MODE_FULL) { + mStatusBar.getNotificationShadeWindowView().getWindowInsetsController() + .hide(navigationBars()); + } else { + mStatusBar.getNavigationBarView().getRootView().setVisibility(View.GONE); + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java index 3a1feaa2de14..28ba1257524d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java @@ -26,10 +26,12 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; import android.provider.Settings.Global; +import android.telephony.AccessNetworkConstants; import android.telephony.Annotation; import android.telephony.CdmaEriInformation; import android.telephony.CellSignalStrength; import android.telephony.CellSignalStrengthCdma; +import android.telephony.DataSpecificRegistrationInfo; import android.telephony.NetworkRegistrationInfo; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; @@ -321,9 +323,9 @@ public class MobileSignalController extends SignalController< private int getNumLevels() { if (mInflateSignalStrengths) { - return SignalStrength.NUM_SIGNAL_STRENGTH_BINS + 1; + return CellSignalStrength.getNumSignalStrengthLevels() + 1; } - return SignalStrength.NUM_SIGNAL_STRENGTH_BINS; + return CellSignalStrength.getNumSignalStrengthLevels(); } @Override @@ -616,10 +618,19 @@ public class MobileSignalController extends SignalController< notifyListenersIfNecessary(); } + private int getNrState(ServiceState serviceState) { + NetworkRegistrationInfo nri = serviceState.getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + if (nri != null) { + return nri.getNrState(); + } + return NetworkRegistrationInfo.NR_STATE_NONE; + } + private MobileIconGroup getNr5GIconGroup() { if (mServiceState == null) return null; - int nrState = mServiceState.getNrState(); + int nrState = getNrState(mServiceState); if (nrState == NetworkRegistrationInfo.NR_STATE_CONNECTED) { // Check if the NR 5G is using millimeter wave and the icon is config. if (mServiceState.getNrFrequencyRange() == ServiceState.FREQUENCY_RANGE_MMWAVE) { @@ -772,12 +783,24 @@ public class MobileSignalController extends SignalController< if (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE) { if (isCarrierSpecificDataIcon()) { mCAPlus = true; - } else if (mServiceState != null && mServiceState.isUsingCarrierAggregation()) { + } else if (mServiceState != null && isUsingCarrierAggregation(mServiceState)) { mCA = true; } } } + private boolean isUsingCarrierAggregation(ServiceState serviceState) { + NetworkRegistrationInfo nri = serviceState.getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + if (nri != null) { + DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo(); + if (dsri != null) { + return dsri.isUsingCarrierAggregation(); + } + } + return false; + } + @Override public void onDataActivity(int direction) { if (DEBUG) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index 6dd113377ce7..46143ca0dd24 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -41,9 +41,9 @@ import android.os.Looper; import android.os.PersistableBundle; import android.provider.Settings; import android.telephony.CarrierConfigManager; +import android.telephony.CellSignalStrength; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; -import android.telephony.SignalStrength; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; @@ -56,7 +56,6 @@ import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.telephony.TelephonyIntents; import com.android.settingslib.net.DataUsageController; import com.android.systemui.DemoMode; import com.android.systemui.Dumpable; @@ -605,7 +604,7 @@ public class NetworkControllerImpl extends BroadcastReceiver @VisibleForTesting void doUpdateMobileControllers() { List<SubscriptionInfo> subscriptions = mSubscriptionManager - .getActiveSubscriptionInfoList(false); + .getActiveAndHiddenSubscriptionInfoList(); if (subscriptions == null) { subscriptions = Collections.emptyList(); } @@ -1035,7 +1034,7 @@ public class NetworkControllerImpl extends BroadcastReceiver if (level != null) { controller.getState().level = level.equals("null") ? -1 : Math.min(Integer.parseInt(level), - SignalStrength.NUM_SIGNAL_STRENGTH_BINS); + CellSignalStrength.getNumSignalStrengthLevels()); controller.getState().connected = controller.getState().level >= 0; } if (args.containsKey("inflate")) { diff --git a/packages/SystemUI/src/com/android/systemui/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java index 47454cb5aca1..cfa2947eb862 100644 --- a/packages/SystemUI/src/com/android/systemui/util/Utils.java +++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java @@ -129,8 +129,6 @@ public class Utils { */ public static boolean useQsMediaPlayer(Context context) { int flag = Settings.System.getInt(context.getContentResolver(), "qs_media_player", 0); - flag |= Settings.System.getInt(context.getContentResolver(), "npv_plugin_flag", 0); - return flag > 0; } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java index eccf09633f16..ea6cf3329772 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java @@ -249,7 +249,7 @@ public class CarrierTextControllerTest extends SysuiTestCase { // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the // same answer as KeyguardUpdateMonitor. Remove when this is addressed - when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn( + when(mSubscriptionManager.getActiveAndHiddenSubscriptionInfoList()).thenReturn( new ArrayList<>()); when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn( diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index 59eb6c59a2cd..795cbb92fefe 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -22,7 +22,6 @@ import static android.telephony.SubscriptionManager.NAME_SOURCE_DEFAULT; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; @@ -483,7 +482,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { List<SubscriptionInfo> list = new ArrayList<>(); list.add(TEST_SUBSCRIPTION); list.add(TEST_SUBSCRIPTION_2); - when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list); + when(mSubscriptionManager.getActiveAndHiddenSubscriptionInfoList()).thenReturn(list); mKeyguardUpdateMonitor.mPhoneStateListener.onActiveDataSubscriptionIdChanged( TEST_SUBSCRIPTION_2.getSubscriptionId()); mTestableLooper.processAllMessages(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java index 0723a4ce74a4..f4cf314aa8fd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java @@ -142,7 +142,7 @@ public class DozeMachineTest extends SysuiTestCase { public void testPulseDone_goesToDoze() { when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(false); mMachine.requestState(INITIALIZED); - mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION); + mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); mMachine.requestState(DOZE_PULSING); mMachine.requestState(DOZE_PULSE_DONE); @@ -155,7 +155,7 @@ public class DozeMachineTest extends SysuiTestCase { public void testPulseDone_goesToAoD() { when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true); mMachine.requestState(INITIALIZED); - mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION); + mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); mMachine.requestState(DOZE_PULSING); mMachine.requestState(DOZE_PULSE_DONE); @@ -168,7 +168,7 @@ public class DozeMachineTest extends SysuiTestCase { public void testPulseDone_afterDocked_goesToDockedAoD() { when(mDockManager.isDocked()).thenReturn(true); mMachine.requestState(INITIALIZED); - mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION); + mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); mMachine.requestState(DOZE_PULSING); mMachine.requestState(DOZE_PULSE_DONE); @@ -183,7 +183,7 @@ public class DozeMachineTest extends SysuiTestCase { when(mDockManager.isDocked()).thenReturn(true); when(mDockManager.isHidden()).thenReturn(true); mMachine.requestState(INITIALIZED); - mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION); + mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); mMachine.requestState(DOZE_PULSING); mMachine.requestState(DOZE_PULSE_DONE); @@ -227,7 +227,7 @@ public class DozeMachineTest extends SysuiTestCase { public void testWakeLock_heldInPulseStates() { mMachine.requestState(INITIALIZED); - mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION); + mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); assertTrue(mWakeLockFake.isHeld()); mMachine.requestState(DOZE_PULSING); @@ -250,7 +250,7 @@ public class DozeMachineTest extends SysuiTestCase { mMachine.requestState(INITIALIZED); mMachine.requestState(DOZE); - mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION); + mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); mMachine.requestState(DOZE_PULSING); mMachine.requestState(DOZE_PULSE_DONE); @@ -262,9 +262,9 @@ public class DozeMachineTest extends SysuiTestCase { mMachine.requestState(INITIALIZED); mMachine.requestState(DOZE); - mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION); + mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); mMachine.requestState(DOZE_PULSING); - mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION); + mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); mMachine.requestState(DOZE_PULSE_DONE); } @@ -273,7 +273,7 @@ public class DozeMachineTest extends SysuiTestCase { mMachine.requestState(INITIALIZED); mMachine.requestState(DOZE); - mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION); + mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); mMachine.requestState(DOZE_PULSE_DONE); } @@ -286,7 +286,7 @@ public class DozeMachineTest extends SysuiTestCase { return null; }).when(mPartMock).transitionTo(any(), eq(DOZE_REQUEST_PULSE)); - mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION); + mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); assertEquals(DOZE_PULSING, mMachine.getState()); } @@ -295,9 +295,9 @@ public class DozeMachineTest extends SysuiTestCase { public void testPulseReason_getMatchesRequest() { mMachine.requestState(INITIALIZED); mMachine.requestState(DOZE); - mMachine.requestPulse(DozeEvent.REASON_SENSOR_DOUBLE_TAP); + mMachine.requestPulse(DozeLog.REASON_SENSOR_DOUBLE_TAP); - assertEquals(DozeEvent.REASON_SENSOR_DOUBLE_TAP, mMachine.getPulseReason()); + assertEquals(DozeLog.REASON_SENSOR_DOUBLE_TAP, mMachine.getPulseReason()); } @Test @@ -309,7 +309,7 @@ public class DozeMachineTest extends SysuiTestCase { if (newState == DOZE_REQUEST_PULSE || newState == DOZE_PULSING || newState == DOZE_PULSE_DONE) { - assertEquals(DozeEvent.PULSE_REASON_NOTIFICATION, mMachine.getPulseReason()); + assertEquals(DozeLog.PULSE_REASON_NOTIFICATION, mMachine.getPulseReason()); } else { assertTrue("unexpected state " + newState, newState == DOZE || newState == DOZE_AOD); @@ -317,7 +317,7 @@ public class DozeMachineTest extends SysuiTestCase { return null; }).when(mPartMock).transitionTo(any(), any()); - mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION); + mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION); mMachine.requestState(DOZE_PULSING); mMachine.requestState(DOZE_PULSE_DONE); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java index 775acdf58c64..ff03fbae3f3a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java @@ -115,14 +115,14 @@ public class DozeSensorsTest extends SysuiTestCase { mWakeLockScreenListener.onSensorChanged(mock(SensorManagerPlugin.SensorEvent.class)); mTestableLooper.processAllMessages(); - verify(mCallback).onSensorPulse(eq(DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN), + verify(mCallback).onSensorPulse(eq(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN), anyFloat(), anyFloat(), eq(null)); mDozeSensors.requestTemporaryDisable(); reset(mCallback); mWakeLockScreenListener.onSensorChanged(mock(SensorManagerPlugin.SensorEvent.class)); mTestableLooper.processAllMessages(); - verify(mCallback, never()).onSensorPulse(eq(DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN), + verify(mCallback, never()).onSensorPulse(eq(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN), anyFloat(), anyFloat(), eq(null)); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java index bf1060905f10..debc9d6430e0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java @@ -165,10 +165,10 @@ public class DozeTriggersTest extends SysuiTestCase { @Test public void testProximitySensorNotAvailablel() { mProximitySensor.setSensorAvailable(false); - mTriggers.onSensor(DozeEvent.PULSE_REASON_SENSOR_LONG_PRESS, 100, 100, null); - mTriggers.onSensor(DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN, 100, 100, + mTriggers.onSensor(DozeLog.PULSE_REASON_SENSOR_LONG_PRESS, 100, 100, null); + mTriggers.onSensor(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN, 100, 100, new float[]{1}); - mTriggers.onSensor(DozeEvent.REASON_SENSOR_TAP, 100, 100, null); + mTriggers.onSensor(DozeLog.REASON_SENSOR_TAP, 100, 100, null); } private void waitForSensorManager() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/recents/model/TaskKeyLruCacheTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/recents/model/TaskKeyLruCacheTest.java deleted file mode 100644 index de6c87c7ff01..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/shared/recents/model/TaskKeyLruCacheTest.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.shared.recents.model; - - -import static junit.framework.TestCase.assertEquals; -import static junit.framework.TestCase.assertNull; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import android.test.suitebuilder.annotation.SmallTest; - -import com.android.systemui.SysuiTestCase; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; - -@SmallTest -@RunWith(MockitoJUnitRunner.class) -public class TaskKeyLruCacheTest extends SysuiTestCase { - private static int sCacheSize = 3; - private static int sIdTask1 = 1; - private static int sIdTask2 = 2; - private static int sIdTask3 = 3; - private static int sIdUser1 = 1; - - TaskKeyLruCache.EvictionCallback mEvictionCallback; - - TaskKeyLruCache<Integer> mCache; - private Task.TaskKey mKey1; - private Task.TaskKey mKey2; - private Task.TaskKey mKey3; - - @Before - public void setup() { - mEvictionCallback = mock(TaskKeyLruCache.EvictionCallback.class); - mCache = new TaskKeyLruCache<>(sCacheSize, mEvictionCallback); - - mKey1 = new Task.TaskKey(sIdTask1, 0, null, null, sIdUser1, System.currentTimeMillis()); - mKey2 = new Task.TaskKey(sIdTask2, 0, null, null, sIdUser1, System.currentTimeMillis()); - mKey3 = new Task.TaskKey(sIdTask3, 0, null, null, sIdUser1, System.currentTimeMillis()); - } - - @Test - public void addSingleItem_get_success() { - mCache.put(mKey1, 1); - - assertEquals(1, (int) mCache.get(mKey1)); - } - - @Test - public void addSingleItem_getUninsertedItem_returnsNull() { - mCache.put(mKey1, 1); - - assertNull(mCache.get(mKey2)); - } - - @Test - public void emptyCache_get_returnsNull() { - assertNull(mCache.get(mKey1)); - } - - @Test - public void updateItem_get_returnsSecond() { - mCache.put(mKey1, 1); - mCache.put(mKey1, 2); - - assertEquals(2, (int) mCache.get(mKey1)); - assertEquals(1, mCache.mKeys.size()); - } - - @Test - public void fillCache_put_evictsOldest() { - mCache.put(mKey1, 1); - mCache.put(mKey2, 2); - mCache.put(mKey3, 3); - Task.TaskKey key4 = new Task.TaskKey(sIdTask3 + 1, 0, - null, null, sIdUser1, System.currentTimeMillis()); - mCache.put(key4, 4); - - assertNull(mCache.get(mKey1)); - assertEquals(3, mCache.mKeys.size()); - assertEquals(mKey2, mCache.mKeys.valueAt(0)); - verify(mEvictionCallback, times(1)).onEntryEvicted(mKey1); - } - - @Test - public void fillCache_remove_success() { - mCache.put(mKey1, 1); - mCache.put(mKey2, 2); - mCache.put(mKey3, 3); - - mCache.remove(mKey2); - - assertNull(mCache.get(mKey2)); - assertEquals(2, mCache.mKeys.size()); - verify(mEvictionCallback, times(0)).onEntryEvicted(mKey2); - } - - @Test - public void put_evictionCallback_notCalled() { - mCache.put(mKey1, 1); - verify(mEvictionCallback, times(0)).onEntryEvicted(mKey1); - } - - @Test - public void evictAll_evictionCallback_called() { - mCache.put(mKey1, 1); - mCache.evictAllCache(); - verify(mEvictionCallback, times(1)).onEntryEvicted(mKey1); - } - - @Test - public void trimAll_evictionCallback_called() { - mCache.put(mKey1, 1); - mCache.put(mKey2, 2); - mCache.trimToSize(-1); - verify(mEvictionCallback, times(1)).onEntryEvicted(mKey1); - verify(mEvictionCallback, times(1)).onEntryEvicted(mKey2); - - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java index 3c6a69882d44..a6e29181e435 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java @@ -36,7 +36,6 @@ import androidx.test.filters.SmallTest; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.SysuiTestCase; import com.android.systemui.assist.AssistManager; -import com.android.systemui.doze.DozeEvent; import com.android.systemui.doze.DozeHost; import com.android.systemui.doze.DozeLog; import com.android.systemui.keyguard.KeyguardViewMediator; @@ -144,13 +143,13 @@ public class DozeServiceHostTest extends SysuiTestCase { @Override public void onPulseFinished() { } - }, DozeEvent.PULSE_REASON_NOTIFICATION); + }, DozeLog.PULSE_REASON_NOTIFICATION); ArgumentCaptor<DozeHost.PulseCallback> pulseCallbackArgumentCaptor = ArgumentCaptor.forClass(DozeHost.PulseCallback.class); verify(mDozeScrimController).pulse( - pulseCallbackArgumentCaptor.capture(), eq(DozeEvent.PULSE_REASON_NOTIFICATION)); + pulseCallbackArgumentCaptor.capture(), eq(DozeLog.PULSE_REASON_NOTIFICATION)); verify(mStatusBar).updateScrimController(); reset(mStatusBar); @@ -162,21 +161,21 @@ public class DozeServiceHostTest extends SysuiTestCase { @Test public void testPulseWhileDozing_notifyAuthInterrupt() { HashSet<Integer> reasonsWantingAuth = new HashSet<>( - Collections.singletonList(DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN)); + Collections.singletonList(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN)); HashSet<Integer> reasonsSkippingAuth = new HashSet<>( - Arrays.asList(DozeEvent.PULSE_REASON_INTENT, - DozeEvent.PULSE_REASON_NOTIFICATION, - DozeEvent.PULSE_REASON_SENSOR_SIGMOTION, - DozeEvent.REASON_SENSOR_PICKUP, - DozeEvent.REASON_SENSOR_DOUBLE_TAP, - DozeEvent.PULSE_REASON_SENSOR_LONG_PRESS, - DozeEvent.PULSE_REASON_DOCKING, - DozeEvent.REASON_SENSOR_WAKE_UP, - DozeEvent.REASON_SENSOR_TAP)); + Arrays.asList(DozeLog.PULSE_REASON_INTENT, + DozeLog.PULSE_REASON_NOTIFICATION, + DozeLog.PULSE_REASON_SENSOR_SIGMOTION, + DozeLog.REASON_SENSOR_PICKUP, + DozeLog.REASON_SENSOR_DOUBLE_TAP, + DozeLog.PULSE_REASON_SENSOR_LONG_PRESS, + DozeLog.PULSE_REASON_DOCKING, + DozeLog.REASON_SENSOR_WAKE_UP, + DozeLog.REASON_SENSOR_TAP)); HashSet<Integer> reasonsThatDontPulse = new HashSet<>( - Arrays.asList(DozeEvent.REASON_SENSOR_PICKUP, - DozeEvent.REASON_SENSOR_DOUBLE_TAP, - DozeEvent.REASON_SENSOR_TAP)); + Arrays.asList(DozeLog.REASON_SENSOR_PICKUP, + DozeLog.REASON_SENSOR_DOUBLE_TAP, + DozeLog.REASON_SENSOR_TAP)); doAnswer(invocation -> { DozeHost.PulseCallback callback = invocation.getArgument(0); @@ -185,7 +184,7 @@ public class DozeServiceHostTest extends SysuiTestCase { }).when(mDozeScrimController).pulse(any(), anyInt()); mDozeServiceHost.mWakeLockScreenPerformsAuth = true; - for (int i = 0; i < DozeEvent.TOTAL_REASONS; i++) { + for (int i = 0; i < DozeLog.TOTAL_REASONS; i++) { reset(mKeyguardUpdateMonitor); mDozeServiceHost.pulseWhileDozing(mock(DozeHost.PulseCallback.class), i); if (reasonsWantingAuth.contains(i)) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java index 1f37ad8b2b1c..5fb71599e2a0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java @@ -55,7 +55,6 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.doze.DozeLog; import com.android.systemui.plugins.FalsingManager; -import com.android.systemui.shared.plugins.PluginManager; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.FlingAnimationUtils; import com.android.systemui.statusbar.KeyguardAffordanceView; @@ -133,8 +132,6 @@ public class NotificationPanelViewTest extends SysuiTestCase { @Mock private DynamicPrivacyController mDynamicPrivacyController; @Mock - private PluginManager mPluginManager; - @Mock private ShadeController mShadeController; @Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager; @@ -218,7 +215,7 @@ public class NotificationPanelViewTest extends SysuiTestCase { mNotificationPanelViewController = new NotificationPanelViewController(mView, mInjectionInflationController, coordinator, expansionHandler, mDynamicPrivacyController, mKeyguardBypassController, - mFalsingManager, mPluginManager, mShadeController, + mFalsingManager, mShadeController, mNotificationLockscreenUserManager, mNotificationEntryManager, mKeyguardStateController, mStatusBarStateController, mDozeLog, mDozeParameters, mCommandQueue, mVibratorHelper, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java index cc3c3ccdc316..294d546e087b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java @@ -30,6 +30,7 @@ import static org.mockito.Matchers.eq; import static org.mockito.Matchers.isA; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -43,6 +44,7 @@ import android.os.Handler; import android.provider.Settings; import android.provider.Settings.Global; import android.telephony.CdmaEriInformation; +import android.telephony.CellSignalStrength; import android.telephony.NetworkRegistrationInfo; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; @@ -56,7 +58,6 @@ import android.util.Log; import androidx.test.InstrumentationRegistry; -import com.android.internal.telephony.cdma.EriInfo; import com.android.settingslib.graph.SignalDrawable; import com.android.settingslib.net.DataUsageController; import com.android.systemui.R; @@ -95,6 +96,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase { protected PhoneStateListener mPhoneStateListener; protected SignalStrength mSignalStrength; protected ServiceState mServiceState; + protected NetworkRegistrationInfo mFakeRegInfo; protected ConnectivityManager mMockCm; protected WifiManager mMockWm; protected SubscriptionManager mMockSm; @@ -158,6 +160,14 @@ public class NetworkControllerBaseTest extends SysuiTestCase { mSignalStrength = mock(SignalStrength.class); mServiceState = mock(ServiceState.class); + mFakeRegInfo = new NetworkRegistrationInfo.Builder() + .setTransportType(TRANSPORT_TYPE_WWAN) + .setDomain(DOMAIN_PS) + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) + .build(); + doReturn(mFakeRegInfo).when(mServiceState) + .getNetworkRegistrationInfo(DOMAIN_PS, TRANSPORT_TYPE_WWAN); + mEriInformation = new CdmaEriInformation(CdmaEriInformation.ERI_OFF, CdmaEriInformation.ERI_ICON_MODE_NORMAL); when(mMockTm.getCdmaEriInformation()).thenReturn(mEriInformation); @@ -219,7 +229,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase { subs.add(subscription); } when(mMockSm.getActiveSubscriptionInfoList()).thenReturn(subs); - when(mMockSm.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(subs); + when(mMockSm.getActiveAndHiddenSubscriptionInfoList()).thenReturn(subs); mNetworkController.doUpdateMobileControllers(); } @@ -405,7 +415,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase { typeIconArg.capture(), dataInArg.capture(), dataOutArg.capture(), anyString(), anyString(), anyBoolean(), anyInt(), anyBoolean()); IconState iconState = iconArg.getValue(); - int state = SignalDrawable.getState(icon, SignalStrength.NUM_SIGNAL_STRENGTH_BINS, + int state = SignalDrawable.getState(icon, CellSignalStrength.getNumSignalStrengthLevels(), false); assertEquals("Visibility in, quick settings", visible, iconState.visible); assertEquals("Signal icon in, quick settings", state, iconState.icon); @@ -440,7 +450,8 @@ public class NetworkControllerBaseTest extends SysuiTestCase { IconState iconState = iconArg.getValue(); int state = icon == -1 ? 0 - : SignalDrawable.getState(icon, SignalStrength.NUM_SIGNAL_STRENGTH_BINS, !inet); + : SignalDrawable.getState(icon, CellSignalStrength.getNumSignalStrengthLevels(), + !inet); assertEquals("Signal icon in status bar", state, iconState.icon); assertEquals("Data icon in status bar", typeIcon, (int) typeIconArg.getValue()); assertEquals("Visibility in status bar", visible, iconState.visible); @@ -483,7 +494,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase { IconState iconState = iconArg.getValue(); - int numSignalStrengthBins = SignalStrength.NUM_SIGNAL_STRENGTH_BINS; + int numSignalStrengthBins = CellSignalStrength.getNumSignalStrengthLevels(); if (mMobileSignalController.mInflateSignalStrengths) { numSignalStrengthBins++; icon++; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java index f6c750db56b7..1eb59396e525 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java @@ -187,7 +187,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { TelephonyManager.NETWORK_TYPE_LTE); updateDataActivity(TelephonyManager.DATA_ACTIVITY_INOUT); ServiceState ss = Mockito.mock(ServiceState.class); - doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(ss).getNrState(); + setNrState(ss, NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED); mPhoneStateListener.onServiceStateChanged(ss); verifyLastMobileDataIndicators(true, DEFAULT_SIGNAL_STRENGTH, TelephonyIcons.ICON_5G, @@ -202,7 +202,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { TelephonyManager.NETWORK_TYPE_LTE); updateDataActivity(TelephonyManager.DATA_ACTIVITY_DORMANT); ServiceState ss = Mockito.mock(ServiceState.class); - doReturn(NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED).when(ss).getNrState(); + setNrState(ss, NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED); mPhoneStateListener.onServiceStateChanged(ss); verifyDataIndicators(TelephonyIcons.ICON_5G); @@ -215,7 +215,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { updateDataConnectionState(TelephonyManager.DATA_CONNECTED, TelephonyManager.NETWORK_TYPE_LTE); ServiceState ss = Mockito.mock(ServiceState.class); - doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(ss).getNrState(); + setNrState(ss, NetworkRegistrationInfo.NR_STATE_CONNECTED); doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(ss).getNrFrequencyRange(); mPhoneStateListener.onServiceStateChanged(ss); @@ -229,7 +229,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { updateDataConnectionState(TelephonyManager.DATA_CONNECTED, TelephonyManager.NETWORK_TYPE_LTE); ServiceState ss = Mockito.mock(ServiceState.class); - doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(ss).getNrState(); + setNrState(ss, NetworkRegistrationInfo.NR_STATE_CONNECTED); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(ss).getNrFrequencyRange(); mPhoneStateListener.onServiceStateChanged(ss); @@ -243,7 +243,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { updateDataConnectionState(TelephonyManager.DATA_CONNECTED, TelephonyManager.NETWORK_TYPE_LTE); ServiceState ss = Mockito.mock(ServiceState.class); - doReturn(NetworkRegistrationInfo.NR_STATE_RESTRICTED).when(ss).getNrState(); + setNrState(ss, NetworkRegistrationInfo.NR_STATE_RESTRICTED); mPhoneStateListener.onServiceStateChanged(mServiceState); verifyDataIndicators(TelephonyIcons.ICON_LTE); @@ -259,7 +259,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { ServiceState ss = Mockito.mock(ServiceState.class); // While nrIconDisplayGracePeriodMs > 0 & is Nr5G, mIsShowingIconGracefully should be true - doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(ss).getNrState(); + setNrState(ss, NetworkRegistrationInfo.NR_STATE_CONNECTED); doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(ss).getNrFrequencyRange(); mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED, TelephonyManager.NETWORK_TYPE_LTE); @@ -278,7 +278,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { assertTrue(mConfig.nrIconDisplayGracePeriodMs == 0); // While nrIconDisplayGracePeriodMs <= 0, mIsShowingIconGracefully should be false - doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); + setNrState(mServiceState, NetworkRegistrationInfo.NR_STATE_CONNECTED); doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(mServiceState).getNrFrequencyRange(); mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED, TelephonyManager.NETWORK_TYPE_LTE); @@ -295,7 +295,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { mPhoneStateListener.onServiceStateChanged(mServiceState); ServiceState ss = Mockito.mock(ServiceState.class); - doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(ss).getNrState(); + setNrState(ss, NetworkRegistrationInfo.NR_STATE_CONNECTED); doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(ss).getNrFrequencyRange(); mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED, TelephonyManager.NETWORK_TYPE_LTE); @@ -305,7 +305,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { // Enabled timer Nr5G switch to None Nr5G, showing 5G icon gracefully ServiceState ssLte = Mockito.mock(ServiceState.class); - doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(ssLte).getNrState(); + setNrState(ssLte, NetworkRegistrationInfo.NR_STATE_NONE); doReturn(ServiceState.FREQUENCY_RANGE_UNKNOWN).when(ssLte).getNrFrequencyRange(); mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED, TelephonyManager.NETWORK_TYPE_LTE); @@ -321,14 +321,14 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { setupDefaultSignal(); mNetworkController.handleConfigurationChanged(); - doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); + setNrState(mServiceState, NetworkRegistrationInfo.NR_STATE_CONNECTED); doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(mServiceState).getNrFrequencyRange(); mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED, TelephonyManager.NETWORK_TYPE_LTE); verifyDataIndicators(TelephonyIcons.ICON_5G); - doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(mServiceState).getNrState(); + setNrState(mServiceState, NetworkRegistrationInfo.NR_STATE_NONE); doReturn(ServiceState.FREQUENCY_RANGE_UNKNOWN).when(mServiceState).getNrFrequencyRange(); mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED, TelephonyManager.NETWORK_TYPE_LTE); @@ -342,7 +342,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { setupDefaultNr5GIconDisplayGracePeriodTime_enableThirtySeconds(); setupDefaultSignal(); mNetworkController.handleConfigurationChanged(); - doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState(); + setNrState(mServiceState, NetworkRegistrationInfo.NR_STATE_CONNECTED); doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(mServiceState).getNrFrequencyRange(); mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED, TelephonyManager.NETWORK_TYPE_LTE); @@ -352,7 +352,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { // Disabled timer, when out of service, reset timer to display latest state updateDataConnectionState(TelephonyManager.DATA_CONNECTED, TelephonyManager.NETWORK_TYPE_LTE); - doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(mServiceState).getNrState(); + setNrState(mServiceState, NetworkRegistrationInfo.NR_STATE_NONE); doReturn(ServiceState.FREQUENCY_RANGE_UNKNOWN).when(mServiceState).getNrFrequencyRange(); mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_DISCONNECTED, TelephonyManager.NETWORK_TYPE_UMTS); @@ -369,7 +369,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { mPhoneStateListener.onServiceStateChanged(mServiceState); ServiceState ss5G = Mockito.mock(ServiceState.class); - doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(ss5G).getNrState(); + setNrState(ss5G, NetworkRegistrationInfo.NR_STATE_CONNECTED); doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(ss5G).getNrFrequencyRange(); mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED, TelephonyManager.NETWORK_TYPE_LTE); @@ -379,7 +379,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { // When timeout enabled, 5G/5G+ switching should be updated immediately ServiceState ss5GPlus = Mockito.mock(ServiceState.class); - doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(ss5GPlus).getNrState(); + setNrState(ss5GPlus, NetworkRegistrationInfo.NR_STATE_CONNECTED); doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(ss5GPlus).getNrFrequencyRange(); mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED, TelephonyManager.NETWORK_TYPE_LTE); @@ -396,22 +396,21 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { mNetworkController.handleConfigurationChanged(); mPhoneStateListener.onServiceStateChanged(mServiceState); - ServiceState ss5G = Mockito.mock(ServiceState.class); - doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(ss5G).getNrState(); - doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(ss5G).getNrFrequencyRange(); + ServiceState ss = Mockito.mock(ServiceState.class); + setNrState(ss, NetworkRegistrationInfo.NR_STATE_CONNECTED); + doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(ss).getNrFrequencyRange(); mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED, TelephonyManager.NETWORK_TYPE_LTE); - mPhoneStateListener.onServiceStateChanged(ss5G); + mPhoneStateListener.onServiceStateChanged(ss); verifyDataIndicators(TelephonyIcons.ICON_5G); // State from NR_5G to NONE NR_5G with timeout, should show previous 5G icon - ServiceState ssLte = Mockito.mock(ServiceState.class); - doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(ssLte).getNrState(); - doReturn(ServiceState.FREQUENCY_RANGE_UNKNOWN).when(ssLte).getNrFrequencyRange(); + setNrState(ss, NetworkRegistrationInfo.NR_STATE_NONE); + doReturn(ServiceState.FREQUENCY_RANGE_UNKNOWN).when(ss).getNrFrequencyRange(); mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED, TelephonyManager.NETWORK_TYPE_LTE); - mPhoneStateListener.onServiceStateChanged(ssLte); + mPhoneStateListener.onServiceStateChanged(ss); verifyDataIndicators(TelephonyIcons.ICON_5G); @@ -420,14 +419,7 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { mNetworkController.handleConfigurationChanged(); // State from NR_5G to NONE NR_STATE_RESTRICTED, showing corresponding icon - doReturn(NetworkRegistrationInfo.NR_STATE_RESTRICTED).when(mServiceState).getNrState(); - NetworkRegistrationInfo fakeRegInfo = new NetworkRegistrationInfo.Builder() - .setTransportType(TRANSPORT_TYPE_WWAN) - .setDomain(DOMAIN_PS) - .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) - .build(); - doReturn(fakeRegInfo).when(mServiceState) - .getNetworkRegistrationInfo(DOMAIN_PS, TRANSPORT_TYPE_WWAN); + setNrState(ss, NetworkRegistrationInfo.NR_STATE_RESTRICTED); mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED, TelephonyManager.NETWORK_TYPE_LTE); @@ -531,4 +523,10 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { true, DEFAULT_QS_SIGNAL_STRENGTH, dataIcon, false, false); } + + private void setNrState(ServiceState ss, int nrState) { + mFakeRegInfo.setNrState(nrState); + doReturn(mFakeRegInfo).when(ss) + .getNetworkRegistrationInfo(DOMAIN_PS, TRANSPORT_TYPE_WWAN); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java index 4406248ec9ea..f52c8c17bfa5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java @@ -136,7 +136,7 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { @Test public void testSignalStrength() { for (int testStrength = 0; - testStrength < SignalStrength.NUM_SIGNAL_STRENGTH_BINS; testStrength++) { + testStrength < CellSignalStrength.getNumSignalStrengthLevels(); testStrength++) { setupDefaultSignal(); setLevel(testStrength); @@ -153,7 +153,7 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { @Test public void testCdmaSignalStrength() { for (int testStrength = 0; - testStrength < SignalStrength.NUM_SIGNAL_STRENGTH_BINS; testStrength++) { + testStrength < CellSignalStrength.getNumSignalStrengthLevels(); testStrength++) { setupDefaultSignal(); setCdma(); setLevel(testStrength); @@ -167,7 +167,7 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { @Test public void testSignalRoaming() { for (int testStrength = 0; - testStrength < SignalStrength.NUM_SIGNAL_STRENGTH_BINS; testStrength++) { + testStrength < CellSignalStrength.getNumSignalStrengthLevels(); testStrength++) { setupDefaultSignal(); setGsmRoaming(true); setLevel(testStrength); @@ -494,7 +494,7 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { // Carrier network change is true, show special indicator verifyLastMobileDataIndicators(true /* visible */, - SignalDrawable.getCarrierChangeState(SignalStrength.NUM_SIGNAL_STRENGTH_BINS), + SignalDrawable.getCarrierChangeState(CellSignalStrength.getNumSignalStrengthLevels()), 0 /* typeIcon */); // Revert back @@ -525,7 +525,7 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { // Carrier network change is true, show special indicator, no roaming. verifyLastMobileDataIndicators(true /* visible */, - SignalDrawable.getCarrierChangeState(SignalStrength.NUM_SIGNAL_STRENGTH_BINS), + SignalDrawable.getCarrierChangeState(CellSignalStrength.getNumSignalStrengthLevels()), 0 /* typeIcon */, false /* roaming */); @@ -557,7 +557,7 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { // Carrier network change is true, show special indicator, no roaming. verifyLastMobileDataIndicators(true /* visible */, - SignalDrawable.getCarrierChangeState(SignalStrength.NUM_SIGNAL_STRENGTH_BINS), + SignalDrawable.getCarrierChangeState(CellSignalStrength.getNumSignalStrengthLevels()), 0 /* typeIcon */, false /* roaming */); @@ -565,7 +565,7 @@ public class NetworkControllerSignalTest extends NetworkControllerBaseTest { // Roaming should not show. verifyLastMobileDataIndicators(true /* visible */, - SignalDrawable.getCarrierChangeState(SignalStrength.NUM_SIGNAL_STRENGTH_BINS), + SignalDrawable.getCarrierChangeState(CellSignalStrength.getNumSignalStrengthLevels()), 0 /* typeIcon */, false /* roaming */); diff --git a/packages/WAPPushManager/Android.bp b/packages/WAPPushManager/Android.bp index 083dac944936..cd804b2c8514 100644 --- a/packages/WAPPushManager/Android.bp +++ b/packages/WAPPushManager/Android.bp @@ -4,7 +4,6 @@ android_app { name: "WAPPushManager", srcs: ["src/**/*.java"], platform_apis: true, - libs: ["telephony-common"], static_libs: ["android-common"], optimize: { proguard_flags_files: ["proguard.flags"], diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index e28ef0f920e9..4f18f3547449 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -216,7 +216,7 @@ final class AutofillManagerServiceImpl updateRemoteAugmentedAutofillService(); final ComponentName componentName = RemoteInlineSuggestionRenderService - .getServiceComponentName(getContext()); + .getServiceComponentName(getContext(), mUserId); if (componentName != null) { mRemoteInlineSuggestionRenderService = new RemoteInlineSuggestionRenderService( getContext(), componentName, InlineSuggestionRenderService.SERVICE_INTERFACE, diff --git a/services/autofill/java/com/android/server/autofill/RemoteInlineSuggestionRenderService.java b/services/autofill/java/com/android/server/autofill/RemoteInlineSuggestionRenderService.java index f9e08e683b6c..31dc23f0118d 100644 --- a/services/autofill/java/com/android/server/autofill/RemoteInlineSuggestionRenderService.java +++ b/services/autofill/java/com/android/server/autofill/RemoteInlineSuggestionRenderService.java @@ -20,6 +20,7 @@ import static com.android.server.autofill.Helper.sVerbose; import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -86,7 +87,7 @@ final class RemoteInlineSuggestionRenderService extends } @Nullable - private static ServiceInfo getServiceInfo(Context context) { + private static ServiceInfo getServiceInfo(Context context, int userId) { final String packageName = context.getPackageManager().getServicesSystemSharedLibraryPackageName(); if (packageName == null) { @@ -96,8 +97,8 @@ final class RemoteInlineSuggestionRenderService extends final Intent intent = new Intent(InlineSuggestionRenderService.SERVICE_INTERFACE); intent.setPackage(packageName); - final ResolveInfo resolveInfo = context.getPackageManager().resolveService(intent, - PackageManager.GET_SERVICES | PackageManager.GET_META_DATA); + final ResolveInfo resolveInfo = context.getPackageManager().resolveServiceAsUser(intent, + PackageManager.GET_SERVICES | PackageManager.GET_META_DATA, userId); final ServiceInfo serviceInfo = resolveInfo == null ? null : resolveInfo.serviceInfo; if (resolveInfo == null || serviceInfo == null) { Slog.w(TAG, "No valid components found."); @@ -115,8 +116,8 @@ final class RemoteInlineSuggestionRenderService extends } @Nullable - public static ComponentName getServiceComponentName(Context context) { - final ServiceInfo serviceInfo = getServiceInfo(context); + public static ComponentName getServiceComponentName(Context context, @UserIdInt int userId) { + final ServiceInfo serviceInfo = getServiceInfo(context, userId); if (serviceInfo == null) return null; final ComponentName componentName = new ComponentName(serviceInfo.packageName, diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerFilePersistedSettings.java b/services/backup/java/com/android/server/backup/UserBackupManagerFilePersistedSettings.java index 6a1de6378a5e..205b7dda267e 100644 --- a/services/backup/java/com/android/server/backup/UserBackupManagerFilePersistedSettings.java +++ b/services/backup/java/com/android/server/backup/UserBackupManagerFilePersistedSettings.java @@ -16,7 +16,6 @@ package com.android.server.backup; -import static com.android.server.backup.BackupManagerService.DEBUG; import static com.android.server.backup.BackupManagerService.TAG; import android.util.Slog; @@ -33,10 +32,13 @@ final class UserBackupManagerFilePersistedSettings { private static final String BACKUP_ENABLE_FILE = "backup_enabled"; static boolean readBackupEnableState(int userId) { - return readBackupEnableState(UserBackupManagerFiles.getBaseStateDir(userId)); + boolean enabled = readBackupEnableState(UserBackupManagerFiles.getBaseStateDir(userId)); + Slog.d(TAG, "user:" + userId + " readBackupEnableState enabled:" + enabled); + return enabled; } static void writeBackupEnableState(int userId, boolean enable) { + Slog.d(TAG, "user:" + userId + " writeBackupEnableState enable:" + enable); writeBackupEnableState(UserBackupManagerFiles.getBaseStateDir(userId), enable); } @@ -45,15 +47,17 @@ final class UserBackupManagerFilePersistedSettings { if (enableFile.exists()) { try (FileInputStream fin = new FileInputStream(enableFile)) { int state = fin.read(); + if (state != 0 && state != 1) { + // TODO (b/148587496) handle instead of only logging + Slog.e(TAG, "Unexpected enabled state:" + state); + } return state != 0; } catch (IOException e) { // can't read the file; fall through to assume disabled Slog.e(TAG, "Cannot read enable state; assuming disabled"); } } else { - if (DEBUG) { - Slog.i(TAG, "isBackupEnabled() => false due to absent settings file"); - } + Slog.i(TAG, "isBackupEnabled() => false due to absent settings file"); } return false; } @@ -64,7 +68,11 @@ final class UserBackupManagerFilePersistedSettings { try (FileOutputStream fout = new FileOutputStream(stage)) { fout.write(enable ? 1 : 0); fout.close(); - stage.renameTo(enableFile); + boolean renamed = stage.renameTo(enableFile); + if (!renamed) { + // TODO (b/148587496) handle instead of only logging + Slog.e(TAG, "Write enable failed as could not rename staging file to actual"); + } // will be synced immediately by the try-with-resources call to close() } catch (IOException | RuntimeException e) { Slog.e( diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index 3bc93cc13023..e342dd7977fb 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -649,7 +649,7 @@ public class LocationManagerService extends ILocationManager.Stub { mEnabled = new SparseArray<>(1); // initialize last since this lets our reference escape - mProvider = new MockableLocationProvider(mContext, mLock, this); + mProvider = new MockableLocationProvider(mLock, this); // we can assume all users start with disabled location state since the initial state // of all providers is disabled. no need to initialize mEnabled further. @@ -2699,7 +2699,7 @@ public class LocationManagerService extends ILocationManager.Stub { mProviderManagers.add(manager); } - manager.setMockProvider(new MockProvider(mContext, properties)); + manager.setMockProvider(new MockProvider(properties)); } } diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java index 9b1326bc88d7..043f657b7f2c 100644 --- a/services/core/java/com/android/server/MmsServiceBroker.java +++ b/services/core/java/com/android/server/MmsServiceBroker.java @@ -128,13 +128,15 @@ public class MmsServiceBroker extends SystemService { @Override public void sendMessage(int subId, String callingPkg, Uri contentUri, String locationUrl, - Bundle configOverrides, PendingIntent sentIntent) throws RemoteException { + Bundle configOverrides, PendingIntent sentIntent, long messageId) + throws RemoteException { returnPendingIntentWithError(sentIntent); } @Override public void downloadMessage(int subId, String callingPkg, String locationUrl, - Uri contentUri, Bundle configOverrides, PendingIntent downloadedIntent) + Uri contentUri, Bundle configOverrides, PendingIntent downloadedIntent, + long messageId) throws RemoteException { returnPendingIntentWithError(downloadedIntent); } @@ -329,7 +331,8 @@ public class MmsServiceBroker extends SystemService { @Override public void sendMessage(int subId, String callingPkg, Uri contentUri, - String locationUrl, Bundle configOverrides, PendingIntent sentIntent) + String locationUrl, Bundle configOverrides, PendingIntent sentIntent, + long messageId) throws RemoteException { Slog.d(TAG, "sendMessage() by " + callingPkg); mContext.enforceCallingPermission(Manifest.permission.SEND_SMS, "Send MMS message"); @@ -343,13 +346,13 @@ public class MmsServiceBroker extends SystemService { Intent.FLAG_GRANT_READ_URI_PERMISSION, subId); getServiceGuarded().sendMessage(subId, callingPkg, contentUri, locationUrl, - configOverrides, sentIntent); + configOverrides, sentIntent, messageId); } @Override public void downloadMessage(int subId, String callingPkg, String locationUrl, Uri contentUri, Bundle configOverrides, - PendingIntent downloadedIntent) throws RemoteException { + PendingIntent downloadedIntent, long messageId) throws RemoteException { Slog.d(TAG, "downloadMessage() by " + callingPkg); mContext.enforceCallingPermission(Manifest.permission.RECEIVE_MMS, "Download MMS message"); @@ -364,7 +367,7 @@ public class MmsServiceBroker extends SystemService { subId); getServiceGuarded().downloadMessage(subId, callingPkg, locationUrl, contentUri, - configOverrides, downloadedIntent); + configOverrides, downloadedIntent, messageId); } @Override diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index a04f25b0d20c..e17dde9a766e 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -24,6 +24,7 @@ import static android.Manifest.permission.WRITE_MEDIA_STORAGE; import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.OP_LEGACY_STORAGE; +import static android.app.AppOpsManager.OP_MANAGE_EXTERNAL_STORAGE; import static android.app.AppOpsManager.OP_READ_EXTERNAL_STORAGE; import static android.app.AppOpsManager.OP_REQUEST_INSTALL_PACKAGES; import static android.app.AppOpsManager.OP_WRITE_EXTERNAL_STORAGE; @@ -4320,21 +4321,37 @@ class StorageManagerService extends IStorageManager.Stub return true; } - public void onAppOpsChanged(int code, int uid, - @Nullable String packageName, int mode) { - if (code == OP_REQUEST_INSTALL_PACKAGES && mIsFuseEnabled) { - // When using FUSE, we basically have no other choice but to kill the app - // after the app op is either granted or rejected. - final IActivityManager am = ActivityManager.getService(); - try { - am.killApplication(packageName, - UserHandle.getAppId(uid), - UserHandle.USER_ALL, AppOpsManager.opToName(code) + " changed."); - } catch (RemoteException e) { - } + private void killAppForOpChange(int code, int uid, String packageName) { + final IActivityManager am = ActivityManager.getService(); + try { + am.killApplication(packageName, + UserHandle.getAppId(uid), + UserHandle.USER_ALL, AppOpsManager.opToName(code) + " changed."); + } catch (RemoteException e) { + } + } - return; + public void onAppOpsChanged(int code, int uid, @Nullable String packageName, int mode) { + if (mIsFuseEnabled) { + // When using FUSE, we may need to kill the app if the op changes + switch(code) { + case OP_REQUEST_INSTALL_PACKAGES: + // Always kill regardless of op change, to remount apps /storage + killAppForOpChange(code, uid, packageName); + return; + case OP_MANAGE_EXTERNAL_STORAGE: + if (mode != MODE_ALLOWED) { + // Only kill if op is denied, to lose external_storage gid + // Killing when op is granted to pickup the gid automatically, results + // in a bad UX, especially since the gid only gives access to unreliable + // volumes, USB OTGs that are rarely mounted. The app will get the + // external_storage gid on next organic restart. + killAppForOpChange(code, uid, packageName); + return; + } + } } + if (mode == MODE_ALLOWED && (code == OP_READ_EXTERNAL_STORAGE || code == OP_WRITE_EXTERNAL_STORAGE || code == OP_REQUEST_INSTALL_PACKAGES)) { diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java index d7201054dea6..4a65a96e57a1 100644 --- a/services/core/java/com/android/server/am/ActivityManagerConstants.java +++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java @@ -438,14 +438,15 @@ final class ActivityManagerConstants extends ContentObserver { DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, ActivityThread.currentApplication().getMainExecutor(), mOnDeviceConfigChangedListener); - updateMaxCachedProcesses(); + loadDeviceConfigConstants(); + // The following read from Settings. updateActivityStartsLoggingEnabled(); - updateBackgroundActivityStarts(); - updateForceRestrictedBackgroundCheck(); updateForegroundServiceStartsLoggingEnabled(); - updateBackgroundFgsStartsRestriction(); - updateOomAdjUpdatePolicy(); - updateImperceptibleKillExemptions(); + } + + private void loadDeviceConfigConstants() { + mOnDeviceConfigChangedListener.onPropertiesChanged( + DeviceConfig.getProperties(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER)); } public void setOverrideMaxCachedProcesses(int value) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 2b160dddedbb..a2209e848ccd 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -9763,15 +9763,21 @@ public class ActivityManagerService extends IActivityManager.Stub * @param crashInfo describing the context of the error * @return true if the process should exit immediately (WTF is fatal) */ + @Override public boolean handleApplicationWtf(final IBinder app, final String tag, boolean system, - final ApplicationErrorReport.ParcelableCrashInfo crashInfo) { + final ApplicationErrorReport.ParcelableCrashInfo crashInfo, int immediateCallerPid) { final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); - if (system) { - // If this is coming from the system, we could very well have low-level - // system locks held, so we want to do this all asynchronously. And we - // never want this to become fatal, so there is that too. + // If this is coming from the system, we could very well have low-level + // system locks held, so we want to do this all asynchronously. And we + // never want this to become fatal, so there is that too. + // + // Note: "callingPid == Process.myPid())" wouldn't be reliable because even if the caller + // is within the system server, if it calls Log.wtf() without clearning the calling + // identity, callingPid would still be of a remote caller. So we explicltly pass the + // process PID from the caller. + if (system || (immediateCallerPid == Process.myPid())) { mHandler.post(new Runnable() { @Override public void run() { handleApplicationWtfInner(callingUid, callingPid, app, tag, crashInfo); diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 77e83bdfeb32..531bc5d1c7df 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -88,7 +88,6 @@ import android.hardware.camera2.CameraDevice.CAMERA_AUDIO_RESTRICTION; import android.net.Uri; import android.os.AsyncTask; import android.os.Binder; -import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -2062,12 +2061,6 @@ public class AppOpsService extends IAppOpsService.Stub { } private void updatePermissionRevokedCompat(int uid, int switchCode, int mode) { - PackageManagerInternal packageManagerInternal = LocalServices.getService( - PackageManagerInternal.class); - if (packageManagerInternal.getUidTargetSdkVersion(uid) >= Build.VERSION_CODES.M) { - return; - } - PackageManager packageManager = mContext.getPackageManager(); String[] packageNames = packageManager.getPackagesForUid(uid); if (ArrayUtils.isEmpty(packageNames)) { diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java index 2c415570d5fa..25c761ab80ec 100644 --- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java +++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java @@ -188,14 +188,14 @@ public class NetworkNotificationManager { int icon = getIcon(transportType, notifyType); if (notifyType == NotificationType.NO_INTERNET && transportType == TRANSPORT_WIFI) { title = r.getString(R.string.wifi_no_internet, - WifiInfo.removeDoubleQuotes(nai.networkCapabilities.getSSID())); + WifiInfo.sanitizeSsid(nai.networkCapabilities.getSSID())); details = r.getString(R.string.wifi_no_internet_detailed); } else if (notifyType == NotificationType.PRIVATE_DNS_BROKEN) { if (transportType == TRANSPORT_CELLULAR) { title = r.getString(R.string.mobile_no_internet); } else if (transportType == TRANSPORT_WIFI) { title = r.getString(R.string.wifi_no_internet, - WifiInfo.removeDoubleQuotes(nai.networkCapabilities.getSSID())); + WifiInfo.sanitizeSsid(nai.networkCapabilities.getSSID())); } else { title = r.getString(R.string.other_networks_no_internet); } @@ -203,19 +203,19 @@ public class NetworkNotificationManager { } else if (notifyType == NotificationType.PARTIAL_CONNECTIVITY && transportType == TRANSPORT_WIFI) { title = r.getString(R.string.network_partial_connectivity, - WifiInfo.removeDoubleQuotes(nai.networkCapabilities.getSSID())); + WifiInfo.sanitizeSsid(nai.networkCapabilities.getSSID())); details = r.getString(R.string.network_partial_connectivity_detailed); } else if (notifyType == NotificationType.LOST_INTERNET && transportType == TRANSPORT_WIFI) { title = r.getString(R.string.wifi_no_internet, - WifiInfo.removeDoubleQuotes(nai.networkCapabilities.getSSID())); + WifiInfo.sanitizeSsid(nai.networkCapabilities.getSSID())); details = r.getString(R.string.wifi_no_internet_detailed); } else if (notifyType == NotificationType.SIGN_IN) { switch (transportType) { case TRANSPORT_WIFI: title = r.getString(R.string.wifi_available_sign_in, 0); details = r.getString(R.string.network_available_sign_in_detailed, - WifiInfo.removeDoubleQuotes(nai.networkCapabilities.getSSID())); + WifiInfo.sanitizeSsid(nai.networkCapabilities.getSSID())); break; case TRANSPORT_CELLULAR: title = r.getString(R.string.network_available_sign_in, 0); @@ -236,7 +236,7 @@ public class NetworkNotificationManager { break; } } else if (notifyType == NotificationType.LOGGED_IN) { - title = WifiInfo.removeDoubleQuotes(nai.networkCapabilities.getSSID()); + title = WifiInfo.sanitizeSsid(nai.networkCapabilities.getSSID()); details = r.getString(R.string.captive_portal_logged_in_detailed); } else if (notifyType == NotificationType.NETWORK_SWITCH) { String fromTransport = getTransportName(transportType); diff --git a/services/core/java/com/android/server/location/AbstractLocationProvider.java b/services/core/java/com/android/server/location/AbstractLocationProvider.java index 64bca78f294d..997f21c9b6a3 100644 --- a/services/core/java/com/android/server/location/AbstractLocationProvider.java +++ b/services/core/java/com/android/server/location/AbstractLocationProvider.java @@ -177,7 +177,6 @@ public abstract class AbstractLocationProvider { } } - protected final Context mContext; protected final Executor mExecutor; // we use a lock-free implementation to update state to ensure atomicity between updating the @@ -186,13 +185,11 @@ public abstract class AbstractLocationProvider { // before it was set, and should not miss any updates that occur after it was set). private final AtomicReference<InternalState> mInternalState; - protected AbstractLocationProvider(Context context, Executor executor) { - this(context, executor, Collections.singleton(context.getPackageName())); + protected AbstractLocationProvider(Executor executor, Context context) { + this(executor, Collections.singleton(context.getPackageName())); } - protected AbstractLocationProvider(Context context, Executor executor, - Set<String> packageNames) { - mContext = context; + protected AbstractLocationProvider(Executor executor, Set<String> packageNames) { mExecutor = executor; mInternalState = new AtomicReference<>( new InternalState(null, State.EMPTY_STATE.withProviderPackageNames(packageNames))); @@ -202,7 +199,7 @@ public abstract class AbstractLocationProvider { * Sets the listener and returns the state at the moment the listener was set. The listener can * expect to receive all state updates from after this point. */ - State setListener(@Nullable Listener listener) { + protected State setListener(@Nullable Listener listener) { return mInternalState.updateAndGet( internalState -> internalState.withListener(listener)).state; } @@ -210,14 +207,14 @@ public abstract class AbstractLocationProvider { /** * Retrieves the state of the provider. */ - State getState() { + public State getState() { return mInternalState.get().state; } /** * Sets the state of the provider to the new state. */ - void setState(State newState) { + protected void setState(State newState) { InternalState oldInternalState = mInternalState.getAndUpdate( internalState -> internalState.withState(newState)); if (newState.equals(oldInternalState.state)) { @@ -357,7 +354,7 @@ public abstract class AbstractLocationProvider { /** * Always invoked on the provider executor. */ - protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {} + protected abstract void onExtraCommand(int uid, int pid, String command, Bundle extras); /** * Requests a provider to enable itself for the given user id. @@ -370,7 +367,7 @@ public abstract class AbstractLocationProvider { /** * Always invoked on the provider executor. */ - protected void onRequestSetAllowed(boolean allowed) {} + protected abstract void onRequestSetAllowed(boolean allowed); /** * Dumps debug or log information. May be invoked from any thread. diff --git a/services/core/java/com/android/server/location/GnssConfiguration.java b/services/core/java/com/android/server/location/GnssConfiguration.java index 86a84e312899..b3546dc79572 100644 --- a/services/core/java/com/android/server/location/GnssConfiguration.java +++ b/services/core/java/com/android/server/location/GnssConfiguration.java @@ -23,7 +23,8 @@ import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; import android.text.TextUtils; import android.util.Log; -import android.util.StatsLog; + +import com.android.internal.util.FrameworkStatsLog; import libcore.io.IoUtils; @@ -283,7 +284,7 @@ class GnssConfiguration { } private void logConfigurations() { - StatsLog.write(StatsLog.GNSS_CONFIGURATION_REPORTED, + FrameworkStatsLog.write(FrameworkStatsLog.GNSS_CONFIGURATION_REPORTED, getSuplHost(), getSuplPort(0), getC2KHost(), diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index 62fa5ec82aea..bcac4730cb8b 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -63,7 +63,6 @@ import android.telephony.TelephonyManager; import android.telephony.gsm.GsmCellLocation; import android.text.TextUtils; import android.util.Log; -import android.util.StatsLog; import android.util.TimeUtils; import com.android.internal.annotations.GuardedBy; @@ -74,6 +73,7 @@ import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification; import com.android.internal.location.ProviderProperties; import com.android.internal.location.ProviderRequest; import com.android.internal.location.gnssmetrics.GnssMetrics; +import com.android.internal.util.FrameworkStatsLog; import com.android.server.DeviceIdleInternal; import com.android.server.FgThread; import com.android.server.LocalServices; @@ -408,7 +408,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements // Available only on GNSS HAL 2.0 implementations and later. private GnssVisibilityControl mGnssVisibilityControl; - // Handler for processing events + private final Context mContext; private Handler mHandler; private final GnssNetworkConnectivityHandler mNetworkConnectivityHandler; @@ -625,10 +625,11 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } public GnssLocationProvider(Context context) { - super(context, FgThread.getExecutor()); + super(FgThread.getExecutor(), context); ensureInitialized(); + mContext = context; mLooper = FgThread.getHandler().getLooper(); // Create a wake lock @@ -1212,6 +1213,11 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } } + @Override + protected void onRequestSetAllowed(boolean allowed) { + // do nothing - the gnss provider is always allowed + } + private void deleteAidingData(Bundle extras) { int flags; @@ -1825,8 +1831,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } native_send_ni_response(notificationId, userResponse); - StatsLog.write(StatsLog.GNSS_NI_EVENT_REPORTED, - StatsLog.GNSS_NI_EVENT_REPORTED__EVENT_TYPE__NI_RESPONSE, + FrameworkStatsLog.write(FrameworkStatsLog.GNSS_NI_EVENT_REPORTED, + FrameworkStatsLog.GNSS_NI_EVENT_REPORTED__EVENT_TYPE__NI_RESPONSE, notificationId, /* niType= */ 0, /* needNotify= */ false, @@ -1891,8 +1897,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements notification.textEncoding = textEncoding; mNIHandler.handleNiNotification(notification); - StatsLog.write(StatsLog.GNSS_NI_EVENT_REPORTED, - StatsLog.GNSS_NI_EVENT_REPORTED__EVENT_TYPE__NI_REQUEST, + FrameworkStatsLog.write(FrameworkStatsLog.GNSS_NI_EVENT_REPORTED, + FrameworkStatsLog.GNSS_NI_EVENT_REPORTED__EVENT_TYPE__NI_REQUEST, notification.notificationId, notification.niType, notification.needNotify, diff --git a/services/core/java/com/android/server/location/GnssVisibilityControl.java b/services/core/java/com/android/server/location/GnssVisibilityControl.java index dd522b95a938..2b5fc7989d8b 100644 --- a/services/core/java/com/android/server/location/GnssVisibilityControl.java +++ b/services/core/java/com/android/server/location/GnssVisibilityControl.java @@ -36,11 +36,11 @@ import android.os.UserHandle; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; -import android.util.StatsLog; import com.android.internal.R; import com.android.internal.location.GpsNetInitiatedHandler; import com.android.internal.notification.SystemNotificationChannels; +import com.android.internal.util.FrameworkStatsLog; import java.util.Arrays; import java.util.List; @@ -650,7 +650,7 @@ class GnssVisibilityControl { } private void logEvent(NfwNotification notification, boolean isPermissionMismatched) { - StatsLog.write(StatsLog.GNSS_NFW_NOTIFICATION_REPORTED, + FrameworkStatsLog.write(FrameworkStatsLog.GNSS_NFW_NOTIFICATION_REPORTED, notification.mProxyAppPackageName, notification.mProtocolStack, notification.mOtherProtocolStackName, diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java index 1dee7a809c7e..19fb6694bbb5 100644 --- a/services/core/java/com/android/server/location/LocationProviderProxy.java +++ b/services/core/java/com/android/server/location/LocationProviderProxy.java @@ -134,6 +134,7 @@ public class LocationProviderProxy extends AbstractLocationProvider { // also used to synchronized any state changes (setEnabled, setProperties, setState, etc) private final Object mLock = new Object(); + private final Context mContext; private final ServiceWatcher mServiceWatcher; @GuardedBy("mLock") @@ -143,10 +144,11 @@ public class LocationProviderProxy extends AbstractLocationProvider { private LocationProviderProxy(Context context, String action, int enableOverlayResId, int nonOverlayPackageResId) { - // safe to use direct executor since none of our callbacks call back into any code above - // this provider - they simply forward to the proxy service - super(context, DIRECT_EXECUTOR); + // safe to use direct executor even though this class has internal locks - all of our + // callbacks go to oneway binder transactions which cannot possibly be re-entrant + super(DIRECT_EXECUTOR, Collections.emptySet()); + mContext = context; mServiceWatcher = new ServiceWatcher(context, FgThread.getHandler(), action, this::onBind, this::onUnbind, enableOverlayResId, nonOverlayPackageResId); diff --git a/services/core/java/com/android/server/location/LocationUsageLogger.java b/services/core/java/com/android/server/location/LocationUsageLogger.java index 755438b1a413..93e19df01cf3 100644 --- a/services/core/java/com/android/server/location/LocationUsageLogger.java +++ b/services/core/java/com/android/server/location/LocationUsageLogger.java @@ -24,9 +24,9 @@ import android.location.LocationManager; import android.location.LocationRequest; import android.stats.location.LocationStatsEnums; import android.util.Log; -import android.util.StatsLog; import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.FrameworkStatsLog; import java.time.Instant; @@ -61,8 +61,8 @@ public class LocationUsageLogger { boolean isLocationRequestNull = locationRequest == null; boolean isGeofenceNull = geofence == null; - StatsLog.write(StatsLog.LOCATION_MANAGER_API_USAGE_REPORTED, usageType, - apiInUse, packageName, + FrameworkStatsLog.write(FrameworkStatsLog.LOCATION_MANAGER_API_USAGE_REPORTED, + usageType, apiInUse, packageName, isLocationRequestNull ? LocationStatsEnums.PROVIDER_UNKNOWN : bucketizeProvider(locationRequest.getProvider()), @@ -101,7 +101,8 @@ public class LocationUsageLogger { return; } - StatsLog.write(StatsLog.LOCATION_MANAGER_API_USAGE_REPORTED, usageType, apiInUse, + FrameworkStatsLog.write(FrameworkStatsLog.LOCATION_MANAGER_API_USAGE_REPORTED, + usageType, apiInUse, /* package_name= */ null, bucketizeProvider(providerName), LocationStatsEnums.QUALITY_UNKNOWN, diff --git a/services/core/java/com/android/server/location/MockProvider.java b/services/core/java/com/android/server/location/MockProvider.java index bcec8b12b371..b45b66017062 100644 --- a/services/core/java/com/android/server/location/MockProvider.java +++ b/services/core/java/com/android/server/location/MockProvider.java @@ -16,15 +16,18 @@ package com.android.server.location; +import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR; + import android.annotation.Nullable; -import android.content.Context; import android.location.Location; +import android.os.Bundle; import com.android.internal.location.ProviderProperties; import com.android.internal.location.ProviderRequest; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.Collections; /** * A mock location provider used by LocationManagerService to implement test providers. @@ -35,10 +38,9 @@ public class MockProvider extends AbstractLocationProvider { @Nullable private Location mLocation; - public MockProvider(Context context, ProviderProperties properties) { - // using a direct executor is only acceptable because this class is so simple it is trivial - // to verify that it does not acquire any locks or re-enter LMS from callbacks - super(context, Runnable::run); + public MockProvider(ProviderProperties properties) { + // using a direct executor is ok because this class has no locks that could deadlock + super(DIRECT_EXECUTOR, Collections.emptySet()); setProperties(properties); } @@ -59,6 +61,9 @@ public class MockProvider extends AbstractLocationProvider { public void onSetRequest(ProviderRequest request) {} @Override + protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {} + + @Override protected void onRequestSetAllowed(boolean allowed) { setAllowed(allowed); } diff --git a/services/core/java/com/android/server/location/MockableLocationProvider.java b/services/core/java/com/android/server/location/MockableLocationProvider.java index 5b4f008a581b..b0e133061fc6 100644 --- a/services/core/java/com/android/server/location/MockableLocationProvider.java +++ b/services/core/java/com/android/server/location/MockableLocationProvider.java @@ -16,8 +16,9 @@ package com.android.server.location; +import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR; + import android.annotation.Nullable; -import android.content.Context; import android.location.Location; import android.os.Bundle; @@ -68,10 +69,10 @@ public class MockableLocationProvider extends AbstractLocationProvider { * The client should expect that it may being to receive callbacks as soon as this constructor * is invoked. */ - public MockableLocationProvider(Context context, Object ownerLock, Listener listener) { + public MockableLocationProvider(Object ownerLock, Listener listener) { // using a direct executor is acceptable because all inbound calls are delegated to the // actual provider implementations which will use their own executors - super(context, Runnable::run, Collections.emptySet()); + super(DIRECT_EXECUTOR, Collections.emptySet()); mOwnerLock = ownerLock; mRequest = ProviderRequest.EMPTY_REQUEST; @@ -190,11 +191,6 @@ public class MockableLocationProvider extends AbstractLocationProvider { } } - @Override - public State getState() { - return super.getState(); - } - /** * Returns the current location request. */ @@ -204,6 +200,7 @@ public class MockableLocationProvider extends AbstractLocationProvider { } } + @Override protected void onSetRequest(ProviderRequest request) { synchronized (mOwnerLock) { if (request == mRequest) { @@ -218,6 +215,7 @@ public class MockableLocationProvider extends AbstractLocationProvider { } } + @Override protected void onExtraCommand(int uid, int pid, String command, Bundle extras) { synchronized (mOwnerLock) { if (mProvider != null) { @@ -226,6 +224,15 @@ public class MockableLocationProvider extends AbstractLocationProvider { } } + @Override + protected void onRequestSetAllowed(boolean allowed) { + synchronized (mOwnerLock) { + if (mProvider != null) { + mProvider.onRequestSetAllowed(allowed); + } + } + } + /** * Dumps the current provider implementation. */ diff --git a/services/core/java/com/android/server/location/PassiveProvider.java b/services/core/java/com/android/server/location/PassiveProvider.java index ef157a39fa28..54dffff8b1df 100644 --- a/services/core/java/com/android/server/location/PassiveProvider.java +++ b/services/core/java/com/android/server/location/PassiveProvider.java @@ -16,9 +16,12 @@ package com.android.server.location; +import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR; + import android.content.Context; import android.location.Criteria; import android.location.Location; +import android.os.Bundle; import com.android.internal.location.ProviderProperties; import com.android.internal.location.ProviderRequest; @@ -49,9 +52,8 @@ public class PassiveProvider extends AbstractLocationProvider { private volatile boolean mReportLocation; public PassiveProvider(Context context) { - // using a direct executor is only acceptable because this class is so simple it is trivial - // to verify that it does not acquire any locks or re-enter LMS from callbacks - super(context, Runnable::run); + // using a direct executor is ok because this class has no locks that could deadlock + super(DIRECT_EXECUTOR, context); mReportLocation = false; @@ -59,15 +61,26 @@ public class PassiveProvider extends AbstractLocationProvider { setAllowed(true); } + /** + * Pass a location into the passive provider. + */ + public void updateLocation(Location location) { + if (mReportLocation) { + reportLocation(location); + } + } + @Override public void onSetRequest(ProviderRequest request) { mReportLocation = request.reportLocation; } - public void updateLocation(Location location) { - if (mReportLocation) { - reportLocation(location); - } + @Override + protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {} + + @Override + protected void onRequestSetAllowed(boolean allowed) { + // do nothing - the passive provider is always allowed } @Override diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 80f6a941bfa0..7104790d0a7c 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -90,10 +90,10 @@ import static android.service.notification.NotificationListenerService.REASON_UN import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED; import static android.service.notification.NotificationListenerService.TRIM_FULL; import static android.service.notification.NotificationListenerService.TRIM_LIGHT; -import static android.util.StatsLogInternal.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING; -import static android.util.StatsLogInternal.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; +import static com.android.internal.util.FrameworkStatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING; +import static com.android.internal.util.FrameworkStatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE; import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER; import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER; import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER; @@ -219,7 +219,6 @@ import android.util.Log; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; -import android.util.StatsLog; import android.util.Xml; import android.util.proto.ProtoOutputStream; import android.view.accessibility.AccessibilityEvent; @@ -232,6 +231,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.compat.IPlatformCompat; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; +import com.android.internal.logging.InstanceIdSequence; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; @@ -243,6 +243,7 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.CollectionUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.FastXmlSerializer; +import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; import com.android.internal.util.function.TriPredicate; @@ -380,6 +381,8 @@ public class NotificationManagerService extends SystemService { private static final String SCHEME_TIMEOUT = "timeout"; private static final String EXTRA_KEY = "key"; + private static final int NOTIFICATION_INSTANCE_ID_MAX = (1 << 13); + /** * Apps that post custom toasts in the background will have those blocked. Apps can * still post toasts created with @@ -519,6 +522,7 @@ public class NotificationManagerService extends SystemService { private final SavePolicyFileRunnable mSavePolicyFile = new SavePolicyFileRunnable(); private NotificationRecordLogger mNotificationRecordLogger; + private InstanceIdSequence mNotificationInstanceIdSequence; private static class Archive { final int mBufferSize; @@ -1718,18 +1722,22 @@ public class NotificationManagerService extends SystemService { } public NotificationManagerService(Context context) { - this(context, new NotificationRecordLoggerImpl()); + this(context, + new NotificationRecordLoggerImpl(), + new InstanceIdSequence(NOTIFICATION_INSTANCE_ID_MAX)); } @VisibleForTesting public NotificationManagerService(Context context, - NotificationRecordLogger notificationRecordLogger) { + NotificationRecordLogger notificationRecordLogger, + InstanceIdSequence notificationInstanceIdSequence) { super(context); mNotificationRecordLogger = notificationRecordLogger; + mNotificationInstanceIdSequence = notificationInstanceIdSequence; Notification.processWhitelistToken = WHITELIST_TOKEN; } - // TODO - replace these methods with a single VisibleForTesting constructor + // TODO - replace these methods with new fields in the VisibleForTesting constructor @VisibleForTesting void setAudioManager(AudioManager audioMananger) { mAudioManager = audioMananger; @@ -5780,14 +5788,14 @@ public class NotificationManagerService extends SystemService { ? intent.resolveActivityInfo(context.getPackageManager(), 0) : null; if (info == null) { - StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName, + FrameworkStatsLog.write(FrameworkStatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName, BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING); Log.w(TAG, "Unable to send as bubble -- couldn't find activity info for intent: " + intent); return false; } if (!ActivityInfo.isResizeableMode(info.resizeMode)) { - StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName, + FrameworkStatsLog.write(FrameworkStatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName, BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE); Log.w(TAG, "Unable to send as bubble -- activity is not resizable for intent: " + intent); @@ -6291,6 +6299,14 @@ public class NotificationManagerService extends SystemService { NotificationRecord old = mNotificationsByKey.get(key); final StatusBarNotification n = r.sbn; final Notification notification = n.getNotification(); + + // Make sure the SBN has an instance ID for statsd logging. + if (old == null || old.sbn.getInstanceId() == null) { + n.setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); + } else { + n.setInstanceId(old.sbn.getInstanceId()); + } + int index = indexOfNotificationLocked(n.getKey()); if (index < 0) { mNotificationList.add(r); diff --git a/services/core/java/com/android/server/notification/NotificationRecordLogger.java b/services/core/java/com/android/server/notification/NotificationRecordLogger.java index 03929e883852..9bbc39249e2e 100644 --- a/services/core/java/com/android/server/notification/NotificationRecordLogger.java +++ b/services/core/java/com/android/server/notification/NotificationRecordLogger.java @@ -138,5 +138,9 @@ public interface NotificationRecordLogger { String assistant = r.getAdjustmentIssuer(); return (assistant == null) ? 0 : assistant.hashCode(); } + + int getInstanceId() { + return (r.sbn.getInstanceId() == null ? 0 : r.sbn.getInstanceId().getId()); + } } } diff --git a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java index d637ad5e368b..00b4c2b060ac 100644 --- a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java +++ b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java @@ -35,7 +35,7 @@ public class NotificationRecordLoggerImpl implements NotificationRecordLogger { /* int32 event_id = 1 */ p.getUiEvent().getId(), /* int32 uid = 2 */ r.getUid(), /* string package_name = 3 */ r.sbn.getPackageName(), - /* int32 instance_id = 4 */ 0, // TODO generate and fill instance ids + /* int32 instance_id = 4 */ p.getInstanceId(), /* int32 notification_id = 5 */ r.sbn.getId(), /* string notification_tag = 6 */ r.sbn.getTag(), /* string channel_id = 7 */ r.sbn.getChannelIdLogTag(), diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java index c6d2b334bd71..90afefffdf2e 100644 --- a/services/core/java/com/android/server/pm/ApexManager.java +++ b/services/core/java/com/android/server/pm/ApexManager.java @@ -96,7 +96,7 @@ public abstract class ApexManager { * depending on whether this device supports APEX, i.e. {@link ApexProperties#updatable()} * evaluates to {@code true}. */ - static ApexManager getInstance() { + public static ApexManager getInstance() { return sApexManagerSingleton.get(); } @@ -272,6 +272,21 @@ public abstract class ApexManager { public abstract String getApexModuleNameForPackageName(String apexPackageName); /** + * Copies the CE apex data directory for the given {@code userId} to a backup location, for use + * in case of rollback. + * + * @return long inode for the snapshot directory if the snapshot was successful, or -1 if not + */ + public abstract long snapshotCeData(int userId, int rollbackId, String apexPackageName); + + /** + * Restores the snapshot of the CE apex data directory for the given {@code userId}. + * + * @return boolean true if the restore was successful + */ + public abstract boolean restoreCeData(int userId, int rollbackId, String apexPackageName); + + /** * Dumps various state information to the provided {@link PrintWriter} object. * * @param pw the {@link PrintWriter} object to send information to. @@ -662,6 +677,45 @@ public abstract class ApexManager { } } + @Override + public long snapshotCeData(int userId, int rollbackId, String apexPackageName) { + populatePackageNameToApexModuleNameIfNeeded(); + String apexModuleName; + synchronized (mLock) { + apexModuleName = mPackageNameToApexModuleName.get(apexPackageName); + } + if (apexModuleName == null) { + Slog.e(TAG, "Invalid apex package name: " + apexPackageName); + return -1; + } + try { + return mApexService.snapshotCeData(userId, rollbackId, apexModuleName); + } catch (Exception e) { + Slog.e(TAG, e.getMessage(), e); + return -1; + } + } + + @Override + public boolean restoreCeData(int userId, int rollbackId, String apexPackageName) { + populatePackageNameToApexModuleNameIfNeeded(); + String apexModuleName; + synchronized (mLock) { + apexModuleName = mPackageNameToApexModuleName.get(apexPackageName); + } + if (apexModuleName == null) { + Slog.e(TAG, "Invalid apex package name: " + apexPackageName); + return false; + } + try { + mApexService.restoreCeData(userId, rollbackId, apexModuleName); + return true; + } catch (Exception e) { + Slog.e(TAG, e.getMessage(), e); + return false; + } + } + /** * Dump information about the packages contained in a particular cache * @param packagesCache the cache to print information about. @@ -865,6 +919,16 @@ public abstract class ApexManager { } @Override + public long snapshotCeData(int userId, int rollbackId, String apexPackageName) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean restoreCeData(int userId, int rollbackId, String apexPackageName) { + throw new UnsupportedOperationException(); + } + + @Override void dump(PrintWriter pw, String packageName) { // No-op } diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 431b4dc280f1..38da8ab26962 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -147,7 +147,6 @@ import java.util.List; import java.util.Objects; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; public class PackageInstallerSession extends IPackageInstallerSession.Stub { private static final String TAG = "PackageInstallerSession"; @@ -736,22 +735,33 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } return result; } - return mFiles.stream().map(fileInfo -> fileInfo.name).toArray(String[]::new); + + String[] result = new String[mFiles.size()]; + for (int i = 0, size = mFiles.size(); i < size; ++i) { + result[i] = mFiles.get(i).name; + } + return result; } - private static File[] filterFiles(File parent, String[] names, FileFilter filter) { - return Arrays.stream(names).map(name -> new File(parent, name)).filter( - file -> filter.accept(file)).toArray(File[]::new); + private static ArrayList<File> filterFiles(File parent, String[] names, FileFilter filter) { + ArrayList<File> result = new ArrayList<>(names.length); + for (String name : names) { + File file = new File(parent, name); + if (filter.accept(file)) { + result.add(file); + } + } + return result; } @GuardedBy("mLock") - private File[] getAddedApksLocked() { + private List<File> getAddedApksLocked() { String[] names = getNamesLocked(); return filterFiles(stageDir, names, sAddedApkFilter); } @GuardedBy("mLock") - private File[] getRemovedFilesLocked() { + private List<File> getRemovedFilesLocked() { String[] names = getNamesLocked(); return filterFiles(stageDir, names, sRemovedFilter); } @@ -1070,11 +1080,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private final class FileSystemConnector extends IPackageInstallerSessionFileSystemConnector.Stub { - final Set<String> mAddedFiles; + final Set<String> mAddedFiles = new ArraySet<>(); FileSystemConnector(List<InstallationFile> addedFiles) { - mAddedFiles = addedFiles.stream().map(file -> file.getName()).collect( - Collectors.toSet()); + for (InstallationFile file : addedFiles) { + mAddedFiles.add(file.getName()); + } } @Override @@ -1741,8 +1752,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @GuardedBy("mLock") private void validateApexInstallLocked() throws PackageManagerException { - final File[] addedFiles = getAddedApksLocked(); - if (ArrayUtils.isEmpty(addedFiles)) { + final List<File> addedFiles = getAddedApksLocked(); + if (addedFiles.isEmpty()) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged"); } @@ -1751,7 +1762,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { "Too many files for apex install"); } - File addedFile = addedFiles[0]; // there is only one file + File addedFile = addedFiles.get(0); // there is only one file // Ensure file name has proper suffix final String sourceName = addedFile.getName(); @@ -1818,9 +1829,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { && params.mode == SessionParams.MODE_INHERIT_EXISTING && VerityUtils.hasFsverity(pkgInfo.applicationInfo.getBaseCodePath()); - final File[] removedFiles = getRemovedFilesLocked(); + final List<File> removedFiles = getRemovedFilesLocked(); final List<String> removeSplitList = new ArrayList<>(); - if (!ArrayUtils.isEmpty(removedFiles)) { + if (!removedFiles.isEmpty()) { for (File removedFile : removedFiles) { final String fileName = removedFile.getName(); final String splitName = fileName.substring( @@ -1829,8 +1840,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } - final File[] addedFiles = getAddedApksLocked(); - if (ArrayUtils.isEmpty(addedFiles) && removeSplitList.size() == 0) { + final List<File> addedFiles = getAddedApksLocked(); + if (addedFiles.isEmpty() && removeSplitList.size() == 0) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged"); } @@ -2449,16 +2460,21 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return true; } - final List<InstallationFile> addedFiles = mFiles.stream().filter( - file -> sAddedFilter.accept(new File(file.name))).map( - file -> new InstallationFile( - file.name, file.lengthBytes, file.metadata)).collect( - Collectors.toList()); - final List<String> removedFiles = mFiles.stream().filter( - file -> sRemovedFilter.accept(new File(file.name))).map( - file -> file.name.substring( - 0, file.name.length() - REMOVE_MARKER_EXTENSION.length())).collect( - Collectors.toList()); + final List<InstallationFile> addedFiles = new ArrayList<>(mFiles.size()); + for (FileInfo file : mFiles) { + if (sAddedFilter.accept(new File(this.stageDir, file.name))) { + addedFiles.add(new InstallationFile( + file.name, file.lengthBytes, file.metadata)); + } + } + final List<String> removedFiles = new ArrayList<>(mFiles.size()); + for (FileInfo file : mFiles) { + if (sRemovedFilter.accept(new File(this.stageDir, file.name))) { + String name = file.name.substring( + 0, file.name.length() - REMOVE_MARKER_EXTENSION.length()); + removedFiles.add(name); + } + } if (mIncrementalFileStorages != null) { for (InstallationFile file : addedFiles) { @@ -3101,8 +3117,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } if (grantedRuntimePermissions.size() > 0) { - params.grantedRuntimePermissions = grantedRuntimePermissions - .stream().toArray(String[]::new); + params.grantedRuntimePermissions = (String[]) grantedRuntimePermissions.toArray(); } if (whitelistedRestrictedPermissions.size() > 0) { @@ -3111,14 +3126,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { int[] childSessionIdsArray; if (childSessionIds.size() > 0) { - childSessionIdsArray = childSessionIds.stream().mapToInt(i -> i).toArray(); + childSessionIdsArray = new int[childSessionIds.size()]; + for (int i = 0, size = childSessionIds.size(); i < size; ++i) { + childSessionIdsArray[i] = childSessionIds.get(i); + } } else { childSessionIdsArray = EMPTY_CHILD_SESSION_ARRAY; } FileInfo[] fileInfosArray = null; if (!files.isEmpty()) { - fileInfosArray = files.stream().toArray(FileInfo[]::new); + fileInfosArray = (FileInfo[]) files.toArray(); } InstallSource installSource = InstallSource.create(installInitiatingPackageName, diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index ae28019a5dea..89354537526c 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -344,12 +344,12 @@ public class StagingManager { } /** + * Perform snapshot and restore as required both for APEXes themselves and for apks in APEX. * Apks inside apex are not installed using apk-install flow. They are scanned from the system * directory directly by PackageManager, as such, RollbackManager need to handle their data * separately here. */ - private void snapshotAndRestoreApkInApexUserData(PackageInstallerSession session) { - // We want to process apks inside apex. So current session needs to contain apex. + private void snapshotAndRestoreForApexSession(PackageInstallerSession session) { if (!sessionContainsApex(session)) { return; } @@ -382,19 +382,37 @@ public class StagingManager { apexSessions.add(session); } - // For each apex, process the apks inside it + final UserManagerInternal um = LocalServices.getService(UserManagerInternal.class); + final int[] allUsers = um.getUserIds(); + IRollbackManager rm = IRollbackManager.Stub.asInterface( + ServiceManager.getService(Context.ROLLBACK_SERVICE)); + for (PackageInstallerSession apexSession : apexSessions) { - List<String> apksInApex = mApexManager.getApksInApex(apexSession.getPackageName()); + String packageName = apexSession.getPackageName(); + // Perform any snapshots or restores for the APEX itself + snapshotAndRestoreApexUserData(packageName, allUsers, rm); + + // Process the apks inside the APEX + List<String> apksInApex = mApexManager.getApksInApex(packageName); for (String apk: apksInApex) { - snapshotAndRestoreApkInApexUserData(apk); + snapshotAndRestoreApkInApexUserData(apk, allUsers, rm); } } } - private void snapshotAndRestoreApkInApexUserData(String packageName) { - IRollbackManager rm = IRollbackManager.Stub.asInterface( - ServiceManager.getService(Context.ROLLBACK_SERVICE)); + private void snapshotAndRestoreApexUserData( + String packageName, int[] allUsers, IRollbackManager rm) { + try { + // appId, ceDataInode, and seInfo are not needed for APEXes + rm.snapshotAndRestoreUserData(packageName, allUsers, 0, 0, + null, 0 /*token*/); + } catch (RemoteException re) { + Slog.e(TAG, "Error snapshotting/restoring user data: " + re); + } + } + private void snapshotAndRestoreApkInApexUserData( + String packageName, int[] allUsers, IRollbackManager rm) { PackageManagerInternal mPmi = LocalServices.getService(PackageManagerInternal.class); AndroidPackage pkg = mPmi.getPackage(packageName); if (pkg == null) { @@ -403,13 +421,11 @@ public class StagingManager { return; } final String seInfo = pkg.getSeInfo(); - final UserManagerInternal um = LocalServices.getService(UserManagerInternal.class); - final int[] allUsers = um.getUserIds(); int appId = -1; long ceDataInode = -1; final PackageSetting ps = (PackageSetting) mPmi.getPackageSetting(packageName); - if (ps != null && rm != null) { + if (ps != null) { appId = ps.appId; ceDataInode = ps.getCeDataInode(UserHandle.USER_SYSTEM); // NOTE: We ignore the user specified in the InstallParam because we know this is @@ -498,7 +514,7 @@ public class StagingManager { abortCheckpoint(); return; } - snapshotAndRestoreApkInApexUserData(session); + snapshotAndRestoreForApexSession(session); Slog.i(TAG, "APEX packages in session " + session.sessionId + " were successfully activated. Proceeding with APK packages, if any"); } diff --git a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java index e6e6e23bf714..e77839c4e5b5 100644 --- a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java +++ b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java @@ -26,6 +26,7 @@ import android.util.SparseLongArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.pm.ApexManager; import com.android.server.pm.Installer; import com.android.server.pm.Installer.InstallerException; @@ -42,9 +43,17 @@ public class AppDataRollbackHelper { private static final String TAG = "RollbackManager"; private final Installer mInstaller; + private final ApexManager mApexManager; public AppDataRollbackHelper(Installer installer) { mInstaller = installer; + mApexManager = ApexManager.getInstance(); + } + + @VisibleForTesting + AppDataRollbackHelper(Installer installer, ApexManager apexManager) { + mInstaller = installer; + mApexManager = apexManager; } /** @@ -55,7 +64,7 @@ public class AppDataRollbackHelper { @GuardedBy("rollback.mLock") // TODO(b/136241838): Move into Rollback and synchronize there. public void snapshotAppData( - int snapshotId, PackageRollbackInfo packageRollbackInfo, int[] userIds) { + int rollbackId, PackageRollbackInfo packageRollbackInfo, int[] userIds) { for (int user : userIds) { final int storageFlags; if (isUserCredentialLocked(user)) { @@ -68,16 +77,7 @@ public class AppDataRollbackHelper { storageFlags = Installer.FLAG_STORAGE_CE | Installer.FLAG_STORAGE_DE; } - try { - long ceSnapshotInode = mInstaller.snapshotAppData( - packageRollbackInfo.getPackageName(), user, snapshotId, storageFlags); - if ((storageFlags & Installer.FLAG_STORAGE_CE) != 0) { - packageRollbackInfo.putCeSnapshotInode(user, ceSnapshotInode); - } - } catch (InstallerException ie) { - Slog.e(TAG, "Unable to create app data snapshot for: " - + packageRollbackInfo.getPackageName() + ", userId: " + user, ie); - } + doSnapshot(packageRollbackInfo, user, rollbackId, storageFlags); } } @@ -119,26 +119,82 @@ public class AppDataRollbackHelper { } } - try { + doRestoreOrWipe(packageRollbackInfo, userId, rollbackId, appId, seInfo, storageFlags); + + return changedRollback; + } + + private boolean doSnapshot( + PackageRollbackInfo packageRollbackInfo, int userId, int rollbackId, int flags) { + if (packageRollbackInfo.isApex()) { + // For APEX, only snapshot CE here + if ((flags & Installer.FLAG_STORAGE_CE) != 0) { + long ceSnapshotInode = mApexManager.snapshotCeData( + userId, rollbackId, packageRollbackInfo.getPackageName()); + if (ceSnapshotInode > 0) { + packageRollbackInfo.putCeSnapshotInode(userId, ceSnapshotInode); + } else { + return false; + } + } + } else { + // APK + try { + long ceSnapshotInode = mInstaller.snapshotAppData( + packageRollbackInfo.getPackageName(), userId, rollbackId, flags); + if ((flags & Installer.FLAG_STORAGE_CE) != 0) { + packageRollbackInfo.putCeSnapshotInode(userId, ceSnapshotInode); + } + } catch (InstallerException ie) { + Slog.e(TAG, "Unable to create app data snapshot for: " + + packageRollbackInfo.getPackageName() + ", userId: " + userId, ie); + return false; + } + } + return true; + } + + private boolean doRestoreOrWipe(PackageRollbackInfo packageRollbackInfo, int userId, + int rollbackId, int appId, String seInfo, int flags) { + if (packageRollbackInfo.isApex()) { switch (packageRollbackInfo.getRollbackDataPolicy()) { case PackageManager.RollbackDataPolicy.WIPE: - mInstaller.clearAppData(null, packageRollbackInfo.getPackageName(), - userId, storageFlags, 0); + // TODO: Implement WIPE for apex CE data break; case PackageManager.RollbackDataPolicy.RESTORE: - mInstaller.restoreAppDataSnapshot(packageRollbackInfo.getPackageName(), appId, - seInfo, userId, rollbackId, storageFlags); + // For APEX, only restore of CE may be done here. + if ((flags & Installer.FLAG_STORAGE_CE) != 0) { + mApexManager.restoreCeData( + userId, rollbackId, packageRollbackInfo.getPackageName()); + } break; default: break; } - } catch (InstallerException ie) { - Slog.e(TAG, "Unable to restore/wipe app data: " - + packageRollbackInfo.getPackageName() + " policy=" - + packageRollbackInfo.getRollbackDataPolicy(), ie); - } + } else { + // APK + try { + switch (packageRollbackInfo.getRollbackDataPolicy()) { + case PackageManager.RollbackDataPolicy.WIPE: + mInstaller.clearAppData(null, packageRollbackInfo.getPackageName(), + userId, flags, 0); + break; + case PackageManager.RollbackDataPolicy.RESTORE: - return changedRollback; + mInstaller.restoreAppDataSnapshot(packageRollbackInfo.getPackageName(), + appId, seInfo, userId, rollbackId, flags); + break; + default: + break; + } + } catch (InstallerException ie) { + Slog.e(TAG, "Unable to restore/wipe app data: " + + packageRollbackInfo.getPackageName() + " policy=" + + packageRollbackInfo.getRollbackDataPolicy(), ie); + return false; + } + } + return true; } /** @@ -204,40 +260,15 @@ public class AppDataRollbackHelper { if (hasPendingBackup) { int idx = pendingBackupUsers.indexOf(userId); - try { - long ceSnapshotInode = mInstaller.snapshotAppData(info.getPackageName(), - userId, rollback.info.getRollbackId(), - Installer.FLAG_STORAGE_CE); - info.putCeSnapshotInode(userId, ceSnapshotInode); + if (doSnapshot( + info, userId, rollback.info.getRollbackId(), Installer.FLAG_STORAGE_CE)) { pendingBackupUsers.remove(idx); - } catch (InstallerException ie) { - Slog.e(TAG, - "Unable to create app data snapshot for: " - + info.getPackageName() + ", userId: " + userId, ie); } } - if (hasPendingRestore) { - try { - switch (info.getRollbackDataPolicy()) { - case PackageManager.RollbackDataPolicy.WIPE: - mInstaller.clearAppData(null, info.getPackageName(), userId, - Installer.FLAG_STORAGE_CE, 0); - break; - case PackageManager.RollbackDataPolicy.RESTORE: - mInstaller.restoreAppDataSnapshot(info.getPackageName(), ri.appId, - ri.seInfo, userId, rollback.info.getRollbackId(), - Installer.FLAG_STORAGE_CE); - break; - default: - break; - } - info.removeRestoreInfo(ri); - } catch (InstallerException ie) { - Slog.e(TAG, "Unable to restore/wipe app data for: " - + info.getPackageName() + " policy=" - + info.getRollbackDataPolicy(), ie); - } + if (hasPendingRestore && doRestoreOrWipe(info, userId, rollback.info.getRollbackId(), + ri.appId, ri.seInfo, Installer.FLAG_STORAGE_CE)) { + info.removeRestoreInfo(ri); } } return foundBackupOrRestore; diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index c50048eeab64..6e479b2b53e0 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -1244,6 +1244,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return mDisplayRotation; } + void setInsetProvider(@InternalInsetsType int type, WindowState win, + @Nullable TriConsumer<DisplayFrames, WindowState, Rect> frameProvider){ + setInsetProvider(type, win, frameProvider, null /* imeFrameProvider */); + } + /** * Marks a window as providing insets for the rest of the windows in the system. * @@ -1251,10 +1256,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo * @param win The window. * @param frameProvider Function to compute the frame, or {@code null} if the just the frame of * the window should be taken. + * @param imeFrameProvider Function to compute the frame when dispatching insets to the IME, or + * {@code null} if the normal frame should be taken. */ void setInsetProvider(@InternalInsetsType int type, WindowState win, - @Nullable TriConsumer<DisplayFrames, WindowState, Rect> frameProvider) { - mInsetsStateController.getSourceProvider(type).setWindow(win, frameProvider); + @Nullable TriConsumer<DisplayFrames, WindowState, Rect> frameProvider, + @Nullable TriConsumer<DisplayFrames, WindowState, Rect> imeFrameProvider) { + mInsetsStateController.getSourceProvider(type).setWindow(win, frameProvider, + imeFrameProvider); } InsetsStateController getInsetsStateController() { @@ -3283,7 +3292,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } computeImeTarget(true /* updateImeTarget */); mInsetsStateController.getSourceProvider(ITYPE_IME).setWindow(win, - null /* frameProvider */); + null /* frameProvider */, null /* imeFrameProvider */); } /** @@ -3407,6 +3416,57 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo && mInputMethodTarget.mActivityRecord.matchParentBounds()); } + /** + * Get IME target that should host IME when this display that is reparented to another + * WindowState. + * IME is never displayed in a child display. + * Use {@link WindowState#getImeControlTarget()} when IME target window + * which originally called + * {@link android.view.inputmethod.InputMethodManager#showSoftInput(View, int)} is known. + * + * @return {@link WindowState} of host that controls IME. + * {@code null} when {@param dc} is not a virtual display. + * @see DisplayContent#reparent + */ + @Nullable + WindowState getImeControlTarget() { + WindowState imeTarget = mInputMethodTarget; + if (imeTarget != null) { + return imeTarget.getImeControlTarget(); + } + + return getInsetsStateController().getImeSourceProvider().getControlTarget().getWindow(); + } + + /** + * Finds the window which can host IME if IME target cannot host it. + * e.g. IME target cannot host IME when it's display has a parent display OR when display + * doesn't support IME/system decorations. + * + * @param target current IME target. + * @return {@link WindowState} that can host IME. + * @see DisplayContent#getImeControlTarget() + */ + WindowState getImeHostOrFallback(WindowState target) { + if (target != null && target.getDisplayContent().canShowIme()) { + return target; + } + + // host is in non-default display that doesn't support system decor, default to + // default display's StatusBar to control IME. + // TODO: (b/148234093)find a better host OR control IME animation/visibility directly + // because it won't work when statusbar isn't available. + return mWmService.getDefaultDisplayContentLocked().getDisplayPolicy().getStatusBar(); + } + + boolean canShowIme() { + if (isUntrustedVirtualDisplay()) { + return false; + } + return mWmService.mDisplayWindowSettings.shouldShowImeLocked(this) + || mWmService.mForceDesktopModeOnExternalDisplays; + } + private void setInputMethodTarget(WindowState target, boolean targetWaitingAnim) { if (target == mInputMethodTarget && mInputMethodTargetWaitingAnim == targetWaitingAnim) { return; @@ -3416,10 +3476,22 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mInputMethodTargetWaitingAnim = targetWaitingAnim; assignWindowLayers(false /* setLayoutNeeded */); mInputMethodControlTarget = computeImeControlTarget(); - mInsetsStateController.onImeTargetChanged(mInputMethodControlTarget); + mInsetsStateController.onImeControlTargetChanged(mInputMethodControlTarget); updateImeParent(); } + /** + * IME control target is the window that controls the IME visibility and animation. + * This window is same as the window on which startInput is called. + * @param target the window that receives IME control. + * + * @see #getImeControlTarget() + */ + void updateImeControlTarget(WindowState target) { + mInputMethodControlTarget = target; + mInsetsStateController.onImeControlTargetChanged(mInputMethodControlTarget); + } + private void updateImeParent() { // Force attaching IME to the display when magnifying, or it would be magnified with // target app together. diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index c6ccd4af06c5..4baf913c2a37 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -1026,7 +1026,12 @@ public class DisplayPolicy { - getNavigationBarHeight(displayFrames.mRotation, mDisplayContent.getConfiguration().uiMode); } - }); + }, + + // For IME we use regular frame. + (displayFrames, windowState, inOutFrame) -> + inOutFrame.set(windowState.getFrameLw())); + mDisplayContent.setInsetProvider(ITYPE_BOTTOM_GESTURES, win, (displayFrames, windowState, inOutFrame) -> { inOutFrame.top -= mBottomGestureAdditionalInset; @@ -3068,7 +3073,9 @@ public class DisplayPolicy { } final InsetsControlTarget controlTarget = swipeTarget.getControllableInsetProvider().getControlTarget(); - if (controlTarget == null) { + + // No transient mode on lockscreen (in notification shade window). + if (controlTarget == null || controlTarget == getNotificationShade()) { return; } if (controlTarget.canShowTransient()) { diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java index fb97ecf8bbc4..3ff1b95dc716 100644 --- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java @@ -16,9 +16,13 @@ package com.android.server.wm; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_IME; + import android.view.InsetsSource; import android.view.WindowInsets; +import com.android.server.protolog.common.ProtoLog; + /** * Controller for IME inset source on the server. It's called provider as it provides the * {@link InsetsSource} to the client that uses it in {@link InsetsSourceConsumer}. @@ -35,40 +39,40 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider { } /** - * Called when a layout pass has occurred. - */ - void onPostLayout() { - super.onPostLayout(); - - if (mImeTargetFromIme != null - && isImeTargetFromDisplayContentAndImeSame() - && mWin != null - && mWin.isDrawnLw() - && !mWin.mGivenInsetsPending) { - mIsImeLayoutDrawn = true; - } - } - - /** - * Called when Insets have been dispatched to client. + * Called when Insets have been dispatched to client. This gets called just after onPostLayout. */ void onPostInsetsDispatched() { - if (mIsImeLayoutDrawn && mShowImeRunner != null) { - // Show IME if InputMethodService requested to be shown and it's layout has finished. - mShowImeRunner.run(); - } + checkShowImePostLayout(); } /** * Called from {@link WindowManagerInternal#showImePostLayout} when {@link InputMethodService} * requests to show IME on {@param imeTarget}. + * * @param imeTarget imeTarget on which IME request is coming from. */ void scheduleShowImePostLayout(WindowState imeTarget) { + boolean targetChanged = mImeTargetFromIme != imeTarget + && mImeTargetFromIme != null && imeTarget != null && mShowImeRunner != null + && mImeTargetFromIme.mActivityRecord == imeTarget.mActivityRecord; mImeTargetFromIme = imeTarget; + if (targetChanged) { + // target changed, check if new target can show IME. + ProtoLog.d(WM_DEBUG_IME, "IME target changed within ActivityRecord"); + checkShowImePostLayout(); + // if IME cannot be shown at this time, it is scheduled to be shown. + // once window that called IMM.showSoftInput() and DisplayContent's ImeTarget match, + // it will be shown. + return; + } + + ProtoLog.d(WM_DEBUG_IME, "Schedule IME show for %s", mImeTargetFromIme.getName()); mShowImeRunner = () -> { + ProtoLog.d(WM_DEBUG_IME, "Run showImeRunner"); // Target should still be the same. if (isImeTargetFromDisplayContentAndImeSame()) { + ProtoLog.d(WM_DEBUG_IME, "call showInsets(ime) on %s", + mDisplayContent.mInputMethodControlTarget.getWindow().getName()); mDisplayContent.mInputMethodControlTarget.showInsets( WindowInsets.Type.ime(), true /* fromIme */); } @@ -76,10 +80,27 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider { }; } + private void checkShowImePostLayout() { + // check if IME is drawn + if (mIsImeLayoutDrawn + || (mImeTargetFromIme != null + && isImeTargetFromDisplayContentAndImeSame() + && mWin != null + && mWin.isDrawnLw() + && !mWin.mGivenInsetsPending)) { + mIsImeLayoutDrawn = true; + // show IME if InputMethodService requested it to be shown. + if (mShowImeRunner != null) { + mShowImeRunner.run(); + } + } + } + /** * Abort any pending request to show IME post layout. */ void abortShowImePostLayout() { + ProtoLog.d(WM_DEBUG_IME, "abortShowImePostLayout"); mImeTargetFromIme = null; mIsImeLayoutDrawn = false; mShowImeRunner = null; @@ -96,12 +117,14 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider { // TODO(b/139861270): Remove the child & sublayer check once IMMS is aware of // actual IME target. final WindowState dcTarget = mDisplayContent.mInputMethodTarget; - if (dcTarget == null) { + if (dcTarget == null || mImeTargetFromIme == null) { return false; } + ProtoLog.d(WM_DEBUG_IME, "dcTarget: %s mImeTargetFromIme: %s", + dcTarget.getName(), mImeTargetFromIme.getName()); + return (!dcTarget.isClosing() && mImeTargetFromIme == dcTarget) || (mImeTargetFromIme != null && dcTarget.getParentWindow() == mImeTargetFromIme - && dcTarget.mSubLayer > mImeTargetFromIme.mSubLayer); + && dcTarget.mSubLayer > mImeTargetFromIme.mSubLayer); } - } diff --git a/services/core/java/com/android/server/wm/InsetsControlTarget.java b/services/core/java/com/android/server/wm/InsetsControlTarget.java index 154cde140810..20e8f2ba485a 100644 --- a/services/core/java/com/android/server/wm/InsetsControlTarget.java +++ b/services/core/java/com/android/server/wm/InsetsControlTarget.java @@ -26,6 +26,13 @@ interface InsetsControlTarget { void notifyInsetsControlChanged(); /** + * @return {@link WindowState} of this target, if any. + */ + default WindowState getWindow() { + return null; + } + + /** * Instructs the control target to show inset sources. * * @param types to specify which types of insets source window should be shown. diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java index fa764e3dfc18..2d4211aa16d8 100644 --- a/services/core/java/com/android/server/wm/InsetsPolicy.java +++ b/services/core/java/com/android/server/wm/InsetsPolicy.java @@ -187,6 +187,10 @@ class InsetsPolicy { if (mShowingTransientTypes.indexOf(ITYPE_STATUS_BAR) != -1) { return mTransientControlTarget; } + if (focusedWin == mPolicy.getNotificationShade()) { + // Notification shade has control anyways, no reason to force anything. + return focusedWin; + } if (areSystemBarsForciblyVisible() || isKeyguardOrStatusBarForciblyVisible()) { return null; } @@ -197,6 +201,10 @@ class InsetsPolicy { if (mShowingTransientTypes.indexOf(ITYPE_NAVIGATION_BAR) != -1) { return mTransientControlTarget; } + if (focusedWin == mPolicy.getNotificationShade()) { + // Notification shade has control anyways, no reason to force anything. + return focusedWin; + } if (areSystemBarsForciblyVisible() || isNavBarForciblyVisible()) { return null; } @@ -204,9 +212,6 @@ class InsetsPolicy { } private boolean isKeyguardOrStatusBarForciblyVisible() { - if (mPolicy.isKeyguardShowing()) { - return true; - } final WindowState statusBar = mPolicy.getStatusBar(); if (statusBar != null) { // TODO(b/118118435): Pretend to the app that it's still able to control it? diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java index 2bb58ddc5b38..db434800c979 100644 --- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java @@ -34,6 +34,7 @@ import android.util.proto.ProtoOutputStream; import android.view.InsetsSource; import android.view.InsetsSourceControl; import android.view.InsetsState; +import android.view.InsetsState.InternalInsetsType; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; @@ -61,6 +62,8 @@ class InsetsSourceProvider { private @Nullable ControlAdapter mAdapter; private TriConsumer<DisplayFrames, WindowState, Rect> mFrameProvider; + private TriConsumer<DisplayFrames, WindowState, Rect> mImeFrameProvider; + private final Rect mImeOverrideFrame = new Rect(); /** The visibility override from the current controlling window. */ private boolean mClientVisible; @@ -111,9 +114,12 @@ class InsetsSourceProvider { * @param win The window that links to this source. * @param frameProvider Based on display frame state and the window, calculates the resulting * frame that should be reported to clients. + * @param imeFrameProvider Based on display frame state and the window, calculates the resulting + * frame that should be reported to IME. */ void setWindow(@Nullable WindowState win, - @Nullable TriConsumer<DisplayFrames, WindowState, Rect> frameProvider) { + @Nullable TriConsumer<DisplayFrames, WindowState, Rect> frameProvider, + @Nullable TriConsumer<DisplayFrames, WindowState, Rect> imeFrameProvider) { if (mWin != null) { if (mControllable) { mWin.setControllableInsetProvider(null); @@ -126,6 +132,7 @@ class InsetsSourceProvider { } mWin = win; mFrameProvider = frameProvider; + mImeFrameProvider = imeFrameProvider; if (win == null) { setServerVisible(false); mSource.setFrame(new Rect()); @@ -162,6 +169,12 @@ class InsetsSourceProvider { } mSource.setFrame(mTmpRect); + if (mImeFrameProvider != null) { + mImeOverrideFrame.set(mWin.getFrameLw()); + mImeFrameProvider.accept(mWin.getDisplayContent().mDisplayFrames, mWin, + mImeOverrideFrame); + } + if (mWin.mGivenVisibleInsets.left != 0 || mWin.mGivenVisibleInsets.top != 0 || mWin.mGivenVisibleInsets.right != 0 || mWin.mGivenVisibleInsets.bottom != 0) { mTmpRect.set(mWin.getFrameLw()); @@ -209,6 +222,12 @@ class InsetsSourceProvider { // to control the window for now. return; } + if (target != null && target.getWindow() != null) { + // ime control target could be a different window. + // Refer WindowState#getImeControlTarget(). + target = target.getWindow().getImeControlTarget(); + } + if (mWin == null) { mControlTarget = target; return; @@ -303,6 +322,21 @@ class InsetsSourceProvider { return sNewInsetsMode == NEW_INSETS_MODE_NONE || mClientVisible; } + /** + * @return Whether this provider uses a different frame to dispatch to the IME. + */ + boolean overridesImeFrame() { + return mImeFrameProvider != null; + } + + /** + * @return Rect to dispatch to the IME as frame. Only valid if {@link #overridesImeFrame()} + * returns {@code true}. + */ + Rect getImeOverrideFrame() { + return mImeOverrideFrame; + } + private class ControlAdapter implements AnimationAdapter { private SurfaceControl mCapturedLeash; diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java index b2234d17984e..568966ae8d2e 100644 --- a/services/core/java/com/android/server/wm/InsetsStateController.java +++ b/services/core/java/com/android/server/wm/InsetsStateController.java @@ -88,6 +88,20 @@ class InsetsStateController { state.removeSource(ITYPE_IME); state.removeSource(ITYPE_STATUS_BAR); } + + // IME needs different frames for certain cases (e.g. navigation bar in gesture nav). + if (type == ITYPE_IME) { + for (int i = mProviders.size() - 1; i >= 0; i--) { + InsetsSourceProvider otherProvider = mProviders.valueAt(i); + if (otherProvider.overridesImeFrame()) { + InsetsSource override = + new InsetsSource(state.getSource(otherProvider.getSource().getType())); + override.setFrame(otherProvider.getImeOverrideFrame()); + state.addSource(override); + } + } + } + return state; } @@ -167,7 +181,7 @@ class InsetsStateController { return mTypeFakeControlTargetMap.get(type) == target; } - void onImeTargetChanged(@Nullable InsetsControlTarget imeTarget) { + void onImeControlTargetChanged(@Nullable InsetsControlTarget imeTarget) { onControlChanged(ITYPE_IME, imeTarget); notifyPendingInsetsControlChanged(); } diff --git a/services/core/java/com/android/server/wm/ProtoLogGroup.java b/services/core/java/com/android/server/wm/ProtoLogGroup.java index 5c2830e13b75..51725cecbc74 100644 --- a/services/core/java/com/android/server/wm/ProtoLogGroup.java +++ b/services/core/java/com/android/server/wm/ProtoLogGroup.java @@ -59,6 +59,8 @@ public enum ProtoLogGroup implements IProtoLogGroup { Consts.TAG_WM), WM_DEBUG_WINDOW_MOVEMENT(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM), + WM_DEBUG_IME(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, + Consts.TAG_WM), TEST_GROUP(true, true, false, "WindowManagetProtoLogTest"); private final boolean mEnabled; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 2c6c756dda3b..229bd2f4afe1 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -6991,8 +6991,15 @@ public class WindowManagerService extends IWindowManager.Stub throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission"); } boolean show; + final DisplayContent dc = mRoot.getDisplayContent(displayId); + if (dc == null) { + ProtoLog.w(WM_ERROR, + "Attempted to get IME flag of a display that does not exist: %d", + displayId); + return false; + } synchronized (mGlobalLock) { - show = shouldShowImeSystemWindowUncheckedLocked(displayId); + show = dc.canShowIme(); } return show; @@ -7291,6 +7298,10 @@ public class WindowManagerService extends IWindowManager.Stub Slog.w(TAG_WM, "updateInputMethodTargetWindow: imeToken=" + imeToken + " imeTargetWindowToken=" + imeTargetWindowToken); } + final WindowState imeTarget = mWindowMap.get(imeTargetWindowToken); + if (imeTarget != null) { + imeTarget.getDisplayContent().updateImeControlTarget(imeTarget); + } } @Override @@ -7405,15 +7416,13 @@ public class WindowManagerService extends IWindowManager.Stub @Override public void showImePostLayout(IBinder imeTargetWindowToken) { synchronized (mGlobalLock) { - final WindowState imeTarget = mWindowMap.get(imeTargetWindowToken); + WindowState imeTarget = mWindowMap.get(imeTargetWindowToken); if (imeTarget == null) { return; } - final int displayId = imeTarget.getDisplayId(); - if (!shouldShowImeSystemWindowUncheckedLocked(displayId)) { - return; - } + imeTarget = imeTarget.getImeControlTarget(); + final int displayId = imeTarget.getDisplayId(); mRoot.getDisplayContent(displayId).getInsetsStateController().getImeSourceProvider() .scheduleShowImePostLayout(imeTarget); } @@ -7423,12 +7432,16 @@ public class WindowManagerService extends IWindowManager.Stub public void hideIme(int displayId) { synchronized (mGlobalLock) { final DisplayContent dc = mRoot.getDisplayContent(displayId); - if (dc != null && dc.mInputMethodTarget != null) { + if (dc != null) { + WindowState imeTarget = dc.getImeControlTarget(); + if (imeTarget == null) { + return; + } // If there was a pending IME show(), reset it as IME has been // requested to be hidden. - dc.getInsetsStateController().getImeSourceProvider().abortShowImePostLayout(); - dc.mInputMethodControlTarget.hideInsets(WindowInsets.Type.ime(), - true /* fromIme */); + imeTarget.getDisplayContent().getInsetsStateController().getImeSourceProvider() + .abortShowImePostLayout(); + imeTarget.hideInsets(WindowInsets.Type.ime(), true /* fromIme */); } } } @@ -7936,21 +7949,6 @@ public class WindowManagerService extends IWindowManager.Stub return true; } - private boolean shouldShowImeSystemWindowUncheckedLocked(final int displayId) { - final DisplayContent displayContent = mRoot.getDisplayContent(displayId); - if (displayContent == null) { - ProtoLog.w(WM_ERROR, - "Attempted to get IME flag of a display that does not exist: %d", - displayId); - return false; - } - if (displayContent.isUntrustedVirtualDisplay()) { - return false; - } - return mDisplayWindowSettings.shouldShowImeLocked(displayContent) - || mForceDesktopModeOnExternalDisplays; - } - @Override public void getWindowInsets(WindowManager.LayoutParams attrs, int displayId, Rect outContentInsets, Rect outStableInsets, diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index aab6b510ef1a..fc04126714d1 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -3518,6 +3518,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } @Override + public WindowState getWindow() { + return this; + } + + @Override public void showInsets(@InsetsType int types, boolean fromIme) { try { mClient.showInsets(types, fromIme); @@ -5334,6 +5339,24 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return false; } + /** + * Get IME target that should host IME when this window's display has a parent. + * Note: IME is never hosted by a display that has a parent. + * When window calling + * {@link android.view.inputmethod.InputMethodManager#showSoftInput(View, int)} is unknown, + * use {@link DisplayContent#getImeControlTarget()} instead. + * + * @return {@link WindowState} of host that controls the IME. + * When window is doesn't have a parent, it is returned as-is. + */ + WindowState getImeControlTarget() { + final DisplayContent dc = getDisplayContent(); + final WindowState parentWindow = dc.getParentWindow(); + + // If target's display has a parent, IME is displayed in the parent display. + return dc.getImeHostOrFallback(parentWindow != null ? parentWindow : this); + } + @Override void assignLayer(Transaction t, int layer) { // See comment in assignRelativeLayerForImeTargetChild diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index d7ea2f53c286..ec3ef7807c3a 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -9553,9 +9553,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @Override - public void setDefaultSmsApplication(ComponentName admin, String packageName) { + public void setDefaultSmsApplication(ComponentName admin, String packageName, boolean parent) { Objects.requireNonNull(admin, "ComponentName is null"); - enforceDeviceOwner(admin); + + if (parent) { + ActiveAdmin ap = getActiveAdminForCallerLocked(admin, + DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER, parent); + enforceProfileOwnerOfOrganizationOwnedDevice(ap); + mInjector.binderWithCleanCallingIdentity(() -> enforcePackageIsSystemPackage( + packageName, getProfileParentId(mInjector.userHandleGetCallingUserId()))); + } else { + enforceDeviceOwner(admin); + } + mInjector.binderWithCleanCallingIdentity(() -> SmsApplication.setDefaultApplication(packageName, mContext)); } @@ -10778,7 +10788,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // API cannot be used to leak if certain non-system package exists in the person // profile. mInjector.binderWithCleanCallingIdentity(() -> - enforcePackageIsSystemPackage(packageName, hidden, userId)); + enforcePackageIsSystemPackage(packageName, userId)); } result = mInjector.binderWithCleanCallingIdentity(() -> mIPackageManager @@ -10811,7 +10821,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { DeviceAdminInfo.USES_POLICY_ORGANIZATION_OWNED_PROFILE_OWNER, parent); // Ensure the package provided is a system package. mInjector.binderWithCleanCallingIdentity(() -> - enforcePackageIsSystemPackage(packageName, false, userId)); + enforcePackageIsSystemPackage(packageName, userId)); } return mInjector.binderWithCleanCallingIdentity( @@ -10819,16 +10829,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } - private void enforcePackageIsSystemPackage(String packageName, boolean hidden, int userId) + private void enforcePackageIsSystemPackage(String packageName, int userId) throws RemoteException { - int flags = PackageManager.MATCH_SYSTEM_ONLY; - // If the package is currently hidden then it is considered uninstalled and - // the MATCH_UNINSTALLED_PACKAGES flag has to be added. - if (!hidden) { - flags |= PackageManager.MATCH_UNINSTALLED_PACKAGES; - } - PackageInfo packageInfo = mIPackageManager.getPackageInfo(packageName, flags, userId); - if (packageInfo == null || !packageInfo.applicationInfo.isSystemApp()) { + if (!isSystemApp(mIPackageManager, packageName, userId)) { throw new IllegalArgumentException( "The provided package is not a system package"); } diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp index 556f6362d872..f99081024494 100644 --- a/services/tests/servicestests/Android.bp +++ b/services/tests/servicestests/Android.bp @@ -30,6 +30,7 @@ android_test { "services.usage", "guava", "androidx.test.core", + "androidx.test.ext.truth", "androidx.test.runner", "androidx.test.rules", "mockito-target-minus-junit4", diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 422c278a3af7..f7a9e5456156 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -2223,17 +2223,13 @@ public class DevicePolicyManagerTest extends DpmTestBase { String packageName = "com.google.android.test"; - PackageInfo packageInfo = new PackageInfo(); - packageInfo.applicationInfo = new ApplicationInfo(); - packageInfo.applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM; + ApplicationInfo applicationInfo = new ApplicationInfo(); + applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM; when(getServices().userManager.getProfileParent(MANAGED_PROFILE_USER_ID)) .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0)); - when(getServices().ipackageManager.getPackageInfo(packageName, - PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM)).thenReturn( - packageInfo); - when(getServices().ipackageManager.getPackageInfo(packageName, - PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.MATCH_SYSTEM_ONLY, - UserHandle.USER_SYSTEM)).thenReturn(packageInfo); + when(getServices().ipackageManager.getApplicationInfo(packageName, + PackageManager.MATCH_UNINSTALLED_PACKAGES, UserHandle.USER_SYSTEM)).thenReturn( + applicationInfo); parentDpm.setApplicationHidden(admin1, packageName, true); verify(getServices().ipackageManager).setApplicationHiddenSettingAsUser(packageName, diff --git a/services/tests/servicestests/src/com/android/server/location/MockableLocationProviderTest.java b/services/tests/servicestests/src/com/android/server/location/MockableLocationProviderTest.java new file mode 100644 index 000000000000..6fafe113d90d --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/location/MockableLocationProviderTest.java @@ -0,0 +1,213 @@ +/* + * 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.location; + +import static androidx.test.ext.truth.location.LocationSubject.assertThat; + +import static com.android.internal.location.ProviderRequest.EMPTY_REQUEST; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.location.Criteria; +import android.location.Location; +import android.platform.test.annotations.Presubmit; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.internal.location.ProviderProperties; +import com.android.internal.location.ProviderRequest; +import com.android.server.location.test.FakeProvider; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.LinkedList; +import java.util.List; + +@Presubmit +@SmallTest +@RunWith(AndroidJUnit4.class) +public class MockableLocationProviderTest { + + private Object mLock; + private ListenerCapture mListener; + + private AbstractLocationProvider mRealProvider; + private MockProvider mMockProvider; + + private MockableLocationProvider mProvider; + + @Before + public void setUp() { + mLock = new Object(); + mListener = new ListenerCapture(); + + mRealProvider = spy(new FakeProvider()); + mMockProvider = spy(new MockProvider(new ProviderProperties( + false, + false, + false, + false, + true, + true, + true, + Criteria.POWER_LOW, + Criteria.ACCURACY_FINE))); + + mProvider = new MockableLocationProvider(mLock, mListener); + mProvider.setRealProvider(mRealProvider); + } + + @Test + public void testSetProvider() { + assertThat(mProvider.getProvider()).isEqualTo(mRealProvider); + + mProvider.setMockProvider(mMockProvider); + assertThat(mProvider.getProvider()).isEqualTo(mMockProvider); + + mProvider.setMockProvider(null); + assertThat(mProvider.getProvider()).isEqualTo(mRealProvider); + + mProvider.setRealProvider(null); + assertThat(mProvider.getProvider()).isNull(); + } + + @Test + public void testSetRequest() { + assertThat(mProvider.getCurrentRequest()).isEqualTo(EMPTY_REQUEST); + verify(mRealProvider, times(1)).onSetRequest(EMPTY_REQUEST); + + ProviderRequest request = new ProviderRequest.Builder().setInterval(1).build(); + mProvider.setRequest(request); + + assertThat(mProvider.getCurrentRequest()).isEqualTo(request); + verify(mRealProvider, times(1)).onSetRequest(request); + + mProvider.setMockProvider(mMockProvider); + assertThat(mProvider.getCurrentRequest()).isEqualTo(request); + verify(mRealProvider, times(2)).onSetRequest(EMPTY_REQUEST); + verify(mMockProvider, times(1)).onSetRequest(request); + + mProvider.setMockProvider(null); + assertThat(mProvider.getCurrentRequest()).isEqualTo(request); + verify(mMockProvider, times(1)).onSetRequest(EMPTY_REQUEST); + verify(mRealProvider, times(2)).onSetRequest(request); + + mProvider.setRealProvider(null); + assertThat(mProvider.getCurrentRequest()).isEqualTo(request); + verify(mRealProvider, times(3)).onSetRequest(EMPTY_REQUEST); + } + + @Test + public void testRequestSetAllowed() { + mProvider.requestSetAllowed(true); + verify(mRealProvider, times(1)).onRequestSetAllowed(true); + + mProvider.setMockProvider(mMockProvider); + mProvider.requestSetAllowed(true); + verify(mMockProvider, times(1)).onRequestSetAllowed(true); + } + + @Test + public void testSendExtraCommand() { + mProvider.sendExtraCommand(0, 0, "command", null); + verify(mRealProvider, times(1)).onExtraCommand(0, 0, "command", null); + + mProvider.setMockProvider(mMockProvider); + mProvider.sendExtraCommand(0, 0, "command", null); + verify(mMockProvider, times(1)).onExtraCommand(0, 0, "command", null); + } + + @Test + public void testSetState() { + assertThat(mProvider.getState().allowed).isFalse(); + + AbstractLocationProvider.State newState; + + mRealProvider.setAllowed(true); + newState = mListener.getNextNewState(); + assertThat(newState).isNotNull(); + assertThat(newState.allowed).isTrue(); + + mProvider.setMockProvider(mMockProvider); + newState = mListener.getNextNewState(); + assertThat(newState).isNotNull(); + assertThat(newState.allowed).isFalse(); + + mMockProvider.setAllowed(true); + newState = mListener.getNextNewState(); + assertThat(newState).isNotNull(); + assertThat(newState.allowed).isTrue(); + + mRealProvider.setAllowed(false); + assertThat(mListener.getNextNewState()).isNull(); + + mProvider.setMockProvider(null); + newState = mListener.getNextNewState(); + assertThat(newState).isNotNull(); + assertThat(newState.allowed).isFalse(); + } + + @Test + public void testReportLocation() { + Location realLocation = new Location("real"); + Location mockLocation = new Location("mock"); + + mRealProvider.reportLocation(realLocation); + assertThat(mListener.getNextLocation()).isEqualTo(realLocation); + + mProvider.setMockProvider(mMockProvider); + mRealProvider.reportLocation(realLocation); + mMockProvider.reportLocation(mockLocation); + assertThat(mListener.getNextLocation()).isEqualTo(mockLocation); + } + + private class ListenerCapture implements AbstractLocationProvider.Listener { + + private final LinkedList<AbstractLocationProvider.State> mNewStates = new LinkedList<>(); + private final LinkedList<Location> mLocations = new LinkedList<>(); + + @Override + public void onStateChanged(AbstractLocationProvider.State oldState, + AbstractLocationProvider.State newState) { + assertThat(Thread.holdsLock(mLock)).isTrue(); + mNewStates.add(newState); + } + + private AbstractLocationProvider.State getNextNewState() { + return mNewStates.poll(); + } + + @Override + public void onReportLocation(Location location) { + assertThat(Thread.holdsLock(mLock)).isTrue(); + mLocations.add(location); + } + + private Location getNextLocation() { + return mLocations.poll(); + } + + @Override + public void onReportLocation(List<Location> locations) {} + } +} diff --git a/services/tests/servicestests/src/com/android/server/location/test/FakeProvider.java b/services/tests/servicestests/src/com/android/server/location/test/FakeProvider.java new file mode 100644 index 000000000000..762080fe5745 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/location/test/FakeProvider.java @@ -0,0 +1,45 @@ +/* + * 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.location.test; + +import android.os.Bundle; + +import com.android.internal.location.ProviderRequest; +import com.android.server.location.AbstractLocationProvider; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.Collections; + +public class FakeProvider extends AbstractLocationProvider { + + public FakeProvider() { + super(Runnable::run, Collections.emptySet()); + } + + @Override + protected void onSetRequest(ProviderRequest request) {} + + @Override + protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {} + + @Override + protected void onRequestSetAllowed(boolean allowed) {} + + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {} +} diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java index 2469cec5766e..118c540a4131 100644 --- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java @@ -336,9 +336,6 @@ public final class UserManagerTest { assertThat(userInfo).isNotNull(); final int userId = userInfo.id; - UserManager userManagerForUser = (UserManager) mContext.createPackageContextAsUser( - "android", 0, asHandle(userId)).getSystemService(Context.USER_SERVICE); - assertThat(mUserManager.hasBadge(userId)).isEqualTo(userTypeDetails.hasBadge()); assertThat(mUserManager.getUserIconBadgeResId(userId)) .isEqualTo(userTypeDetails.getIconBadge()); @@ -346,17 +343,18 @@ public final class UserManagerTest { .isEqualTo(userTypeDetails.getBadgePlain()); assertThat(mUserManager.getUserBadgeNoBackgroundResId(userId)) .isEqualTo(userTypeDetails.getBadgeNoBackground()); - assertThat(mUserManager.isUserOfType(asHandle(userId), userTypeDetails.getName())) - .isTrue(); - assertThat(userManagerForUser.isProfile()).isEqualTo(userTypeDetails.isProfile()); - assertThat(userManagerForUser.isUserOfType(asHandle(userId), userTypeDetails.getName())) - .isTrue(); final int badgeIndex = userInfo.profileBadge; assertThat(mUserManager.getUserBadgeColor(userId)).isEqualTo( Resources.getSystem().getColor(userTypeDetails.getBadgeColor(badgeIndex), null)); assertThat(mUserManager.getBadgedLabelForUser("Test", asHandle(userId))).isEqualTo( Resources.getSystem().getString(userTypeDetails.getBadgeLabel(badgeIndex), "Test")); + + // Test @UserHandleAware methods + final UserManager userManagerForUser = UserManager.get(mContext.createPackageContextAsUser( + "android", 0, asHandle(userId))); + assertThat(userManagerForUser.isUserOfType(userTypeDetails.getName())).isTrue(); + assertThat(userManagerForUser.isProfile()).isEqualTo(userTypeDetails.isProfile()); } // Make sure only max managed profiles can be created diff --git a/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java b/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java index f871203728c0..3ceaac207680 100644 --- a/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java +++ b/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java @@ -27,6 +27,7 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; import android.content.pm.VersionedPackage; import android.content.rollback.PackageRollbackInfo; @@ -34,12 +35,15 @@ import android.content.rollback.PackageRollbackInfo.RestoreInfo; import android.util.IntArray; import android.util.SparseLongArray; +import com.android.server.pm.ApexManager; import com.android.server.pm.Installer; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.mockito.InOrder; +import org.mockito.Mock; import org.mockito.Mockito; import java.io.File; @@ -48,10 +52,17 @@ import java.util.ArrayList; @RunWith(JUnit4.class) public class AppDataRollbackHelperTest { + @Mock private ApexManager mApexManager; + + @Before + public void setUp() { + initMocks(this); + } + @Test public void testSnapshotAppData() throws Exception { Installer installer = mock(Installer.class); - AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer)); + AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer, mApexManager)); // All users are unlocked so we should snapshot data for them. doReturn(true).when(helper).isUserCredentialLocked(eq(10)); @@ -114,7 +125,7 @@ public class AppDataRollbackHelperTest { @Test public void testRestoreAppDataSnapshot_pendingBackupForUser() throws Exception { Installer installer = mock(Installer.class); - AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer)); + AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer, mApexManager)); PackageRollbackInfo info = createPackageRollbackInfo("com.foo"); IntArray pendingBackups = info.getPendingBackups(); @@ -139,7 +150,7 @@ public class AppDataRollbackHelperTest { @Test public void testRestoreAppDataSnapshot_availableBackupForLockedUser() throws Exception { Installer installer = mock(Installer.class); - AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer)); + AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer, mApexManager)); doReturn(true).when(helper).isUserCredentialLocked(eq(10)); PackageRollbackInfo info = createPackageRollbackInfo("com.foo"); @@ -163,7 +174,7 @@ public class AppDataRollbackHelperTest { @Test public void testRestoreAppDataSnapshot_availableBackupForUnlockedUser() throws Exception { Installer installer = mock(Installer.class); - AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer)); + AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer, mApexManager)); doReturn(false).when(helper).isUserCredentialLocked(eq(10)); PackageRollbackInfo info = createPackageRollbackInfo("com.foo"); @@ -184,7 +195,7 @@ public class AppDataRollbackHelperTest { @Test public void destroyAppData() throws Exception { Installer installer = mock(Installer.class); - AppDataRollbackHelper helper = new AppDataRollbackHelper(installer); + AppDataRollbackHelper helper = new AppDataRollbackHelper(installer, mApexManager); PackageRollbackInfo info = createPackageRollbackInfo("com.foo.bar"); info.putCeSnapshotInode(11, 239L); @@ -206,7 +217,7 @@ public class AppDataRollbackHelperTest { @Test public void commitPendingBackupAndRestoreForUser() throws Exception { Installer installer = mock(Installer.class); - AppDataRollbackHelper helper = new AppDataRollbackHelper(installer); + AppDataRollbackHelper helper = new AppDataRollbackHelper(installer, mApexManager); when(installer.snapshotAppData(anyString(), anyInt(), anyInt(), anyInt())).thenReturn(53L); diff --git a/core/java/com/android/internal/logging/testing/InstanceIdSequenceFake.java b/services/tests/uiservicestests/src/com/android/internal/logging/InstanceIdSequenceFake.java index 0fd40b9ceb06..1629ef00b65a 100644 --- a/core/java/com/android/internal/logging/testing/InstanceIdSequenceFake.java +++ b/services/tests/uiservicestests/src/com/android/internal/logging/InstanceIdSequenceFake.java @@ -14,12 +14,7 @@ * limitations under the License. */ -package com.android.internal.logging.testing; - -import android.annotation.SuppressLint; - -import com.android.internal.logging.InstanceId; -import com.android.internal.logging.InstanceIdSequence; +package com.android.internal.logging; /** * A fake implementation of InstanceIdSequence that returns 0, 1, 2, ... @@ -30,27 +25,15 @@ public class InstanceIdSequenceFake extends InstanceIdSequence { super(instanceIdMax); } - /** - * Extend InstanceId to add a constructor we can call, strictly for testing purposes. - * Public so that tests can check whether the InstanceIds they see are fake. - */ - public static class InstanceIdFake extends InstanceId { - @SuppressLint("VisibleForTests") // This is test infrastructure, which ought to count - InstanceIdFake(int id) { - super(id); - } - } - private int mNextId = 0; @Override public InstanceId newInstanceId() { synchronized (this) { - ++mNextId; if (mNextId >= mInstanceIdMax) { mNextId = 0; } - return new InstanceIdFake(mNextId); + return newInstanceIdInternal(mNextId++); } } } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java index 651ad40a4781..f029bc80480a 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java @@ -72,6 +72,8 @@ import android.view.accessibility.IAccessibilityManagerClient; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.logging.InstanceIdSequence; +import com.android.internal.logging.InstanceIdSequenceFake; import com.android.internal.util.IntPair; import com.android.server.UiServiceTestCase; import com.android.server.lights.LogicalLight; @@ -99,6 +101,8 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { @Mock IAccessibilityManager mAccessibilityService; NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake(); + private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake( + 1 << 30); private NotificationManagerService mService; private String mPkg = "com.android.server.notification"; @@ -149,7 +153,8 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { verify(mAccessibilityService).addClient(any(IAccessibilityManagerClient.class), anyInt()); assertTrue(accessibilityManager.isEnabled()); - mService = spy(new NotificationManagerService(getContext(), mNotificationRecordLogger)); + mService = spy(new NotificationManagerService(getContext(), mNotificationRecordLogger, + mNotificationInstanceIdSequence)); mService.setAudioManager(mAudioManager); mService.setVibrator(mVibrator); mService.setSystemReady(true); 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 768b4721a1ee..2cf5eaefcc58 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -148,6 +148,8 @@ import androidx.test.InstrumentationRegistry; import com.android.internal.R; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; +import com.android.internal.logging.InstanceIdSequence; +import com.android.internal.logging.InstanceIdSequenceFake; import com.android.internal.statusbar.NotificationVisibility; import com.android.internal.util.FastXmlSerializer; import com.android.server.LocalServices; @@ -257,7 +259,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Mock NotificationHistoryManager mHistoryManager; NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake(); - + private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake( + 1 << 30); // Use a Testable subclass so we can simulate calls from the system without failing. private static class TestableNotificationManagerService extends NotificationManagerService { @@ -267,8 +270,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Nullable NotificationAssistantAccessGrantedCallback mNotificationAssistantAccessGrantedCallback; - TestableNotificationManagerService(Context context, NotificationRecordLogger logger) { - super(context, logger); + TestableNotificationManagerService(Context context, NotificationRecordLogger logger, + InstanceIdSequence notificationInstanceIdSequence) { + super(context, logger, notificationInstanceIdSequence); } @Override @@ -355,7 +359,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any()); - mService = new TestableNotificationManagerService(mContext, mNotificationRecordLogger); + mService = new TestableNotificationManagerService(mContext, mNotificationRecordLogger, + mNotificationInstanceIdSequence); // Use this testable looper. mTestableLooper = TestableLooper.get(this); @@ -1135,6 +1140,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertEquals(PKG, call.r.sbn.getPackageName()); assertEquals(0, call.r.sbn.getId()); assertEquals(tag, call.r.sbn.getTag()); + assertNotNull(call.r.sbn.getInstanceId()); + assertEquals(0, call.r.sbn.getInstanceId().getId()); } @Test @@ -1151,14 +1158,19 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mBinderService.enqueueNotificationWithTag(PKG, PKG, tag, 0, update, 0); waitForIdle(); assertEquals(2, mNotificationRecordLogger.getCalls().size()); + assertTrue(mNotificationRecordLogger.get(0).shouldLog()); assertEquals( NotificationRecordLogger.NotificationReportedEvents.NOTIFICATION_POSTED, mNotificationRecordLogger.get(0).getUiEvent()); + assertEquals(0, mNotificationRecordLogger.get(0).r.sbn.getInstanceId().getId()); + + assertTrue(mNotificationRecordLogger.get(1).shouldLog()); assertEquals( NotificationRecordLogger.NotificationReportedEvents.NOTIFICATION_UPDATED, mNotificationRecordLogger.get(1).getUiEvent()); - assertTrue(mNotificationRecordLogger.get(1).shouldLog()); + // Instance ID doesn't change on update of an active notification + assertEquals(0, mNotificationRecordLogger.get(1).r.sbn.getInstanceId().getId()); } @Test @@ -1175,6 +1187,34 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + public void testEnqueueNotificationWithTag_LogsAgainAfterCancel() throws Exception { + final String tag = "testEnqueueNotificationWithTag_LogsAgainAfterCancel"; + Notification notification = new Notification.Builder(mContext, + mTestNotificationChannel.getId()) + .setSmallIcon(android.R.drawable.sym_def_app_icon).build(); + mBinderService.enqueueNotificationWithTag(PKG, PKG, tag, 0, notification, 0); + waitForIdle(); + mBinderService.cancelNotificationWithTag(PKG, PKG, tag, 0, 0); + waitForIdle(); + mBinderService.enqueueNotificationWithTag(PKG, PKG, tag, 0, notification, 0); + waitForIdle(); + assertEquals(2, mNotificationRecordLogger.getCalls().size()); + + assertTrue(mNotificationRecordLogger.get(0).shouldLog()); + assertEquals( + NotificationRecordLogger.NotificationReportedEvents.NOTIFICATION_POSTED, + mNotificationRecordLogger.get(0).getUiEvent()); + assertEquals(0, mNotificationRecordLogger.get(0).r.sbn.getInstanceId().getId()); + + assertTrue(mNotificationRecordLogger.get(1).shouldLog()); + assertEquals( + NotificationRecordLogger.NotificationReportedEvents.NOTIFICATION_POSTED, + mNotificationRecordLogger.get(1).getUiEvent()); + // New instance ID because notification was canceled before re-post + assertEquals(1, mNotificationRecordLogger.get(1).r.sbn.getInstanceId().getId()); + } + + @Test public void testCancelNotificationImmediatelyAfterEnqueue() throws Exception { mBinderService.enqueueNotificationWithTag(PKG, PKG, "testCancelNotificationImmediatelyAfterEnqueue", 0, @@ -2309,7 +2349,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testHasCompanionDevice_noService() { - mService = new TestableNotificationManagerService(mContext, mNotificationRecordLogger); + mService = new TestableNotificationManagerService(mContext, mNotificationRecordLogger, + mNotificationInstanceIdSequence); assertFalse(mService.hasCompanionDevice(mListener)); } @@ -4679,8 +4720,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } // cross user, with permission, no problem - TestablePermissions perms = mContext.getTestablePermissions(); - perms.setPermission(android.Manifest.permission.INTERACT_ACROSS_USERS, PERMISSION_GRANTED); + enableInteractAcrossUsers(); mBinderService.canNotifyAsPackage("src", "target", mContext.getUserId() + 1); } @@ -4698,8 +4738,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } // cross user, with permission, no problem - TestablePermissions perms = mContext.getTestablePermissions(); - perms.setPermission(android.Manifest.permission.INTERACT_ACROSS_USERS, PERMISSION_GRANTED); + enableInteractAcrossUsers(); mBinderService.getNotificationChannels("src", "target", mContext.getUserId() + 1); } @@ -5317,8 +5356,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } // cross user, with permission, no problem - TestablePermissions perms = mContext.getTestablePermissions(); - perms.setPermission(android.Manifest.permission.INTERACT_ACROSS_USERS, PERMISSION_GRANTED); + enableInteractAcrossUsers(); mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(), mUid + UserHandle.PER_USER_RANGE); } @@ -5334,12 +5372,16 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } // cross user, with permission, no problem - TestablePermissions perms = mContext.getTestablePermissions(); - perms.setPermission(android.Manifest.permission.INTERACT_ACROSS_USERS, PERMISSION_GRANTED); + enableInteractAcrossUsers(); mBinderService.areBubblesAllowedForPackage(mContext.getPackageName(), mUid + UserHandle.PER_USER_RANGE); } + private void enableInteractAcrossUsers() { + TestablePermissions perms = mContext.getTestablePermissions(); + perms.setPermission(android.Manifest.permission.INTERACT_ACROSS_USERS, PERMISSION_GRANTED); + } + @Test public void testNotificationBubbleChanged_false() throws Exception { // Bubbles are allowed! diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java index 11972fd6a8dc..5c1487f0fdf6 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordLoggerFake.java @@ -23,7 +23,7 @@ import java.util.List; * Fake implementation of NotificationRecordLogger, for testing. */ class NotificationRecordLoggerFake implements NotificationRecordLogger { - class CallRecord extends NotificationRecordPair { + static class CallRecord extends NotificationRecordPair { public int position, buzzBeepBlink; CallRecord(NotificationRecord r, NotificationRecord old, int position, int buzzBeepBlink) { @@ -35,7 +35,7 @@ class NotificationRecordLoggerFake implements NotificationRecordLogger { return shouldLog(buzzBeepBlink); } } - List<CallRecord> mCalls = new ArrayList<CallRecord>(); + private List<CallRecord> mCalls = new ArrayList<CallRecord>(); List<CallRecord> getCalls() { return mCalls; diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java index e18c8919b645..64a980484539 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java @@ -54,6 +54,8 @@ import android.util.ArraySet; import android.util.AtomicFile; import android.util.Pair; +import com.android.internal.logging.InstanceIdSequence; +import com.android.internal.logging.InstanceIdSequenceFake; import com.android.server.LocalServices; import com.android.server.UiServiceTestCase; import com.android.server.lights.LightsManager; @@ -92,12 +94,15 @@ public class RoleObserverTest extends UiServiceTestCase { @Mock private RoleManager mRoleManager; NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake(); - + private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake( + 1 << 30); private List<UserInfo> mUsers; private static class TestableNotificationManagerService extends NotificationManagerService { - TestableNotificationManagerService(Context context, NotificationRecordLogger logger) { - super(context, logger); + TestableNotificationManagerService(Context context, + NotificationRecordLogger logger, + InstanceIdSequence notificationInstanceIdSequence) { + super(context, logger, notificationInstanceIdSequence); } @Override @@ -120,7 +125,8 @@ public class RoleObserverTest extends UiServiceTestCase { mUsers.add(new UserInfo(10, "second", 0)); when(mUm.getUsers()).thenReturn(mUsers); - mService = new TestableNotificationManagerService(mContext, mNotificationRecordLogger); + mService = new TestableNotificationManagerService(mContext, mNotificationRecordLogger, + mNotificationInstanceIdSequence); mRoleObserver = mService.new RoleObserver(mRoleManager, mPm, mExecutor); try { diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java index c3bead7162e6..e71225579989 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java @@ -119,18 +119,6 @@ public class InsetsPolicyTest extends WindowTestsBase { assertNull(controls); } - @Test - public void testControlsForDispatch_keyguard() { - addWindow(TYPE_NOTIFICATION_SHADE, "notificationShade"); - addWindow(TYPE_NAVIGATION_BAR, "navBar"); - mockKeyguardShowing(); - - final InsetsSourceControl[] controls = addAppWindowAndGetControlsForDispatch(); - // The app must not control the top bar. - assertNotNull(controls); - assertEquals(1, controls.length); - } - // TODO: adjust this test if we pretend to the app that it's still able to control it. @Test public void testControlsForDispatch_forceStatusBarVisible() { @@ -159,6 +147,21 @@ public class InsetsPolicyTest extends WindowTestsBase { } @Test + public void testControlsForDispatch_statusBarForceShowNavigation_butFocusedAnyways() { + WindowState notifShade = addWindow(TYPE_NOTIFICATION_SHADE, "notificationShade"); + notifShade.mAttrs.privateFlags |= PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION; + addWindow(TYPE_NAVIGATION_BAR, "navBar"); + + mDisplayContent.getInsetsPolicy().updateBarControlTarget(notifShade); + InsetsSourceControl[] controls + = mDisplayContent.getInsetsStateController().getControlsForDispatch(notifShade); + + // The app controls the navigation bar. + assertNotNull(controls); + assertEquals(1, controls.length); + } + + @Test public void testShowTransientBars_bothCanBeTransient_appGetsBothFakeControls() { addWindow(TYPE_STATUS_BAR, "statusBar") .getControllableInsetProvider().getSource().setVisible(false); @@ -260,10 +263,4 @@ public class InsetsPolicyTest extends WindowTestsBase { mDisplayContent.getInsetsPolicy().updateBarControlTarget(win); return mDisplayContent.getInsetsStateController().getControlsForDispatch(win); } - - private void mockKeyguardShowing() { - final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy(); - spyOn(displayPolicy); - doReturn(true).when(displayPolicy).isKeyguardShowing(); - } } diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java index d819b1ada659..7ffdd7cdceb6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java @@ -57,7 +57,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); statusBar.getFrameLw().set(0, 0, 500, 100); statusBar.mHasSurface = true; - mProvider.setWindow(statusBar, null); + mProvider.setWindow(statusBar, null, null); mProvider.onPostLayout(); assertEquals(new Rect(0, 0, 500, 100), mProvider.getSource().getFrame()); assertEquals(Insets.of(0, 100, 0, 0), @@ -74,7 +74,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { ime.getGivenContentInsetsLw().set(0, 0, 0, 60); ime.getGivenVisibleInsetsLw().set(0, 0, 0, 75); ime.mHasSurface = true; - mProvider.setWindow(ime, null); + mProvider.setWindow(ime, null, null); mProvider.onPostLayout(); assertEquals(new Rect(0, 0, 500, 40), mProvider.getSource().getFrame()); assertEquals(new Rect(0, 0, 500, 25), mProvider.getSource().getVisibleFrame()); @@ -89,7 +89,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { public void testPostLayout_invisible() { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); statusBar.getFrameLw().set(0, 0, 500, 100); - mProvider.setWindow(statusBar, null); + mProvider.setWindow(statusBar, null, null); mProvider.onPostLayout(); assertEquals(Insets.NONE, mProvider.getSource().calculateInsets(new Rect(0, 0, 500, 500), false /* ignoreVisibility */)); @@ -102,7 +102,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { mProvider.setWindow(statusBar, (displayFrames, windowState, rect) -> { rect.set(10, 10, 20, 20); - }); + }, null); mProvider.onPostLayout(); assertEquals(new Rect(10, 10, 20, 20), mProvider.getSource().getFrame()); } @@ -112,7 +112,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); final WindowState target = createWindow(null, TYPE_APPLICATION, "target"); statusBar.getFrameLw().set(0, 0, 500, 100); - mProvider.setWindow(statusBar, null); + mProvider.setWindow(statusBar, null, null); mProvider.updateControlForTarget(target, false /* force */); assertNotNull(mProvider.getControl(target)); mProvider.updateControlForTarget(null, false /* force */); @@ -124,7 +124,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); final WindowState target = createWindow(null, TYPE_APPLICATION, "target"); statusBar.getFrameLw().set(0, 0, 500, 100); - mProvider.setWindow(statusBar, null); + mProvider.setWindow(statusBar, null, null); mProvider.updateControlForFakeTarget(target); assertNotNull(mProvider.getControl(target)); assertNull(mProvider.getControl(target).getLeash()); @@ -137,7 +137,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); final WindowState target = createWindow(null, TYPE_APPLICATION, "target"); statusBar.getFrameLw().set(0, 0, 500, 100); - mProvider.setWindow(statusBar, null); + mProvider.setWindow(statusBar, null, null); mProvider.updateControlForTarget(target, false /* force */); InsetsState state = new InsetsState(); state.getSource(ITYPE_STATUS_BAR).setVisible(false); @@ -150,7 +150,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); final WindowState target = createWindow(null, TYPE_APPLICATION, "target"); statusBar.getFrameLw().set(0, 0, 500, 100); - mProvider.setWindow(statusBar, null); + mProvider.setWindow(statusBar, null, null); InsetsState state = new InsetsState(); state.getSource(ITYPE_STATUS_BAR).setVisible(false); mProvider.onInsetsModified(target, state.getSource(ITYPE_STATUS_BAR)); diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java index d13baeccb68a..39cdd2cb907e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java @@ -21,26 +21,26 @@ import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; import static android.view.InsetsState.ITYPE_STATUS_BAR; import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.view.InsetsSource; import android.view.InsetsSourceControl; import android.view.InsetsState; import android.view.test.InsetsModeSession; -import androidx.test.filters.FlakyTest; -import androidx.test.filters.SmallTest; - import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; +import androidx.test.filters.FlakyTest; +import androidx.test.filters.SmallTest; + @SmallTest @FlakyTest(detail = "Promote to pre-submit once confirmed stable.") @Presubmit @@ -65,7 +65,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { public void testStripForDispatch_notOwn() { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); - getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null); + getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null); statusBar.setControllableInsetProvider(getController().getSourceProvider(ITYPE_STATUS_BAR)); assertNotNull(getController().getInsetsForDispatch(app).getSource(ITYPE_STATUS_BAR)); } @@ -74,7 +74,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { public void testStripForDispatch_own() { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); mDisplayContent.getInsetsStateController().getSourceProvider(ITYPE_STATUS_BAR) - .setWindow(statusBar, null); + .setWindow(statusBar, null, null); statusBar.setControllableInsetProvider(getController().getSourceProvider(ITYPE_STATUS_BAR)); final InsetsState state = getController().getInsetsForDispatch(statusBar); for (int i = state.getSourcesCount() - 1; i >= 0; i--) { @@ -88,19 +88,36 @@ public class InsetsStateControllerTest extends WindowTestsBase { final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar"); final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime"); - getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null); - getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null); - getController().getSourceProvider(ITYPE_IME).setWindow(ime, null); + getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null); + getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null); + getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null); assertEquals(0, getController().getInsetsForDispatch(navBar).getSourcesCount()); } @Test + public void testImeForDispatch() { + final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); + final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime"); + InsetsSourceProvider statusBarProvider = + getController().getSourceProvider(ITYPE_STATUS_BAR); + statusBarProvider.setWindow(statusBar, null, ((displayFrames, windowState, rect) -> + rect.set(0, 1, 2, 3))); + getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null); + statusBar.setControllableInsetProvider(statusBarProvider); + + statusBarProvider.onPostLayout(); + + final InsetsState state = getController().getInsetsForDispatch(ime); + assertEquals(new Rect(0, 1, 2, 3), state.getSource(ITYPE_STATUS_BAR).getFrame()); + } + + @Test public void testBarControllingWinChanged() { final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar"); final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); - getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null); - getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null); + getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null); + getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null); getController().onBarControlTargetChanged(app, null, app, null); InsetsSourceControl[] controls = getController().getControlsForDispatch(app); assertEquals(2, controls.length); @@ -110,7 +127,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { public void testControlRevoked() { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); - getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null); + getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null); getController().onBarControlTargetChanged(app, null, null, null); assertNotNull(getController().getControlsForDispatch(app)); getController().onBarControlTargetChanged(null, null, null, null); @@ -122,7 +139,7 @@ public class InsetsStateControllerTest extends WindowTestsBase { public void testControlRevoked_animation() { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); - getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null); + getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null); getController().onBarControlTargetChanged(app, null, null, null); assertNotNull(getController().getControlsForDispatch(app)); statusBar.cancelAnimation(); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index 186ff6b1515b..2c68cc7a19bf 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -425,7 +425,7 @@ public class WindowStateTests extends WindowTestsBase { statusBar.mHasSurface = true; assertTrue(statusBar.isVisible()); mDisplayContent.getInsetsStateController().getSourceProvider(ITYPE_STATUS_BAR) - .setWindow(statusBar, null /* frameProvider */); + .setWindow(statusBar, null /* frameProvider */, null /* imeFrameProvider */); mDisplayContent.getInsetsStateController().onBarControlTargetChanged( app, null /* fakeTopControlling */, app, null /* fakeNavControlling */); final InsetsSource source = new InsetsSource(ITYPE_STATUS_BAR); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 20eab5a45ff1..8e362ae4c59a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -110,7 +110,7 @@ class WindowTestsBase extends SystemServiceTestsBase { beforeCreateDisplay(); context.getDisplay().getDisplayInfo(mDisplayInfo); - mDisplayContent = createNewDisplay(); + mDisplayContent = createNewDisplay(true /* supportIme */); // Set-up some common windows. mCommonWindows = new HashSet<>(); @@ -349,16 +349,29 @@ class WindowTestsBase extends SystemServiceTestsBase { return WindowTestUtils.createTaskInStack(mWm, stack, userId); } - /** Creates a {@link DisplayContent} and adds it to the system. */ + /** Creates a {@link DisplayContent} that supports IME and adds it to the system. */ DisplayContent createNewDisplay() { - return createNewDisplay(mDisplayInfo); + return createNewDisplay(true /* supportIme */); } /** Creates a {@link DisplayContent} and adds it to the system. */ + private DisplayContent createNewDisplay(boolean supportIme) { + return createNewDisplay(mDisplayInfo, supportIme); + } + + /** Creates a {@link DisplayContent} that supports IME and adds it to the system. */ DisplayContent createNewDisplay(DisplayInfo info) { + return createNewDisplay(info, true /* supportIme */); + } + + /** Creates a {@link DisplayContent} and adds it to the system. */ + private DisplayContent createNewDisplay(DisplayInfo info, boolean supportIme) { final DisplayContent display = new TestDisplayContent.Builder(mWm.mAtmService, info).build(); - return display.mDisplayContent; + final DisplayContent dc = display.mDisplayContent; + // this display can show IME. + dc.mWmService.mDisplayWindowSettings.setShouldShowImeLocked(dc, supportIme); + return dc; } /** @@ -372,7 +385,7 @@ class WindowTestsBase extends SystemServiceTestsBase { DisplayInfo displayInfo = new DisplayInfo(); displayInfo.copyFrom(mDisplayInfo); displayInfo.state = displayState; - return createNewDisplay(displayInfo); + return createNewDisplay(displayInfo, true /* supportIme */); } /** Creates a {@link com.android.server.wm.WindowTestUtils.TestWindowState} */ @@ -389,7 +402,7 @@ class WindowTestsBase extends SystemServiceTestsBase { displayInfo.copyFrom(mDisplayInfo); displayInfo.type = Display.TYPE_VIRTUAL; displayInfo.ownerUid = SYSTEM_UID; - return createNewDisplay(displayInfo); + return createNewDisplay(displayInfo, false /* supportIme */); } /** Sets the default minimum task size to 1 so that tests can use small task sizes */ diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java index 9967bebf20b8..140a95d61100 100644 --- a/services/usb/java/com/android/server/usb/UsbHostManager.java +++ b/services/usb/java/com/android/server/usb/UsbHostManager.java @@ -34,9 +34,9 @@ import android.service.usb.UsbIsHeadsetProto; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Slog; -import android.util.StatsLog; import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.dump.DualDumpOutputStream; import com.android.server.usb.descriptors.UsbDescriptor; @@ -418,10 +418,11 @@ public class UsbHostManager { parser.getRawDescriptors()); // Stats collection - StatsLog.write(StatsLog.USB_DEVICE_ATTACHED, newDevice.getVendorId(), - newDevice.getProductId(), parser.hasAudioInterface(), - parser.hasHIDInterface(), parser.hasStorageInterface(), - StatsLog.USB_DEVICE_ATTACHED__STATE__STATE_CONNECTED, 0); + FrameworkStatsLog.write(FrameworkStatsLog.USB_DEVICE_ATTACHED, + newDevice.getVendorId(), newDevice.getProductId(), + parser.hasAudioInterface(), parser.hasHIDInterface(), + parser.hasStorageInterface(), + FrameworkStatsLog.USB_DEVICE_ATTACHED__STATE__STATE_CONNECTED, 0); } } @@ -454,10 +455,10 @@ public class UsbHostManager { UsbDescriptorParser parser = new UsbDescriptorParser(deviceAddress, current.mDescriptors); // Stats collection - StatsLog.write(StatsLog.USB_DEVICE_ATTACHED, device.getVendorId(), - device.getProductId(), parser.hasAudioInterface(), + FrameworkStatsLog.write(FrameworkStatsLog.USB_DEVICE_ATTACHED, + device.getVendorId(), device.getProductId(), parser.hasAudioInterface(), parser.hasHIDInterface(), parser.hasStorageInterface(), - StatsLog.USB_DEVICE_ATTACHED__STATE__STATE_DISCONNECTED, + FrameworkStatsLog.USB_DEVICE_ATTACHED__STATE__STATE_DISCONNECTED, System.currentTimeMillis() - current.mTimestamp); } } else { diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java index c3e2013eff10..1025bf5d67b0 100644 --- a/services/usb/java/com/android/server/usb/UsbPortManager.java +++ b/services/usb/java/com/android/server/usb/UsbPortManager.java @@ -66,11 +66,11 @@ import android.service.usb.UsbServiceProto; import android.util.ArrayMap; import android.util.Log; import android.util.Slog; -import android.util.StatsLog; import com.android.internal.annotations.GuardedBy; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.notification.SystemNotificationChannels; +import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.dump.DualDumpOutputStream; import com.android.server.FgThread; @@ -1040,8 +1040,9 @@ public class UsbPortManager { if (mConnected.containsKey(portInfo.mUsbPort.getId())) { //Previous logged a connected. Set it to disconnected. if (mConnected.get(portInfo.mUsbPort.getId())) { - StatsLog.write(StatsLog.USB_CONNECTOR_STATE_CHANGED, - StatsLog.USB_CONNECTOR_STATE_CHANGED__STATE__STATE_DISCONNECTED, + FrameworkStatsLog.write(FrameworkStatsLog.USB_CONNECTOR_STATE_CHANGED, + FrameworkStatsLog + .USB_CONNECTOR_STATE_CHANGED__STATE__STATE_DISCONNECTED, portInfo.mUsbPort.getId(), portInfo.mLastConnectDurationMillis); } mConnected.remove(portInfo.mUsbPort.getId()); @@ -1051,7 +1052,7 @@ public class UsbPortManager { //Previous logged a contaminant detected. Set it to not detected. if ((mContaminantStatus.get(portInfo.mUsbPort.getId()) == UsbPortStatus.CONTAMINANT_DETECTION_DETECTED)) { - StatsLog.write(StatsLog.USB_CONTAMINANT_REPORTED, + FrameworkStatsLog.write(FrameworkStatsLog.USB_CONTAMINANT_REPORTED, portInfo.mUsbPort.getId(), convertContaminantDetectionStatusToProto( UsbPortStatus.CONTAMINANT_DETECTION_NOT_DETECTED)); @@ -1065,10 +1066,10 @@ public class UsbPortManager { || (mConnected.get(portInfo.mUsbPort.getId()) != portInfo.mUsbPortStatus.isConnected())) { mConnected.put(portInfo.mUsbPort.getId(), portInfo.mUsbPortStatus.isConnected()); - StatsLog.write(StatsLog.USB_CONNECTOR_STATE_CHANGED, + FrameworkStatsLog.write(FrameworkStatsLog.USB_CONNECTOR_STATE_CHANGED, portInfo.mUsbPortStatus.isConnected() - ? StatsLog.USB_CONNECTOR_STATE_CHANGED__STATE__STATE_CONNECTED : - StatsLog.USB_CONNECTOR_STATE_CHANGED__STATE__STATE_DISCONNECTED, + ? FrameworkStatsLog.USB_CONNECTOR_STATE_CHANGED__STATE__STATE_CONNECTED : + FrameworkStatsLog.USB_CONNECTOR_STATE_CHANGED__STATE__STATE_DISCONNECTED, portInfo.mUsbPort.getId(), portInfo.mLastConnectDurationMillis); } @@ -1077,7 +1078,7 @@ public class UsbPortManager { != portInfo.mUsbPortStatus.getContaminantDetectionStatus())) { mContaminantStatus.put(portInfo.mUsbPort.getId(), portInfo.mUsbPortStatus.getContaminantDetectionStatus()); - StatsLog.write(StatsLog.USB_CONTAMINANT_REPORTED, + FrameworkStatsLog.write(FrameworkStatsLog.USB_CONTAMINANT_REPORTED, portInfo.mUsbPort.getId(), convertContaminantDetectionStatusToProto( portInfo.mUsbPortStatus.getContaminantDetectionStatus())); diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java index b230e4bbf8a2..43d5bf323abb 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java @@ -292,9 +292,27 @@ public final class UsbDescriptorParser { // Clean up descriptor.postParse(stream); } catch (Exception ex) { - Log.e(TAG, "Exception parsing USB descriptors.", ex); + // Clean up, compute error status + descriptor.postParse(stream); - // Clean up + // Report + Log.w(TAG, "Exception parsing USB descriptors. type:0x" + descriptor.getType() + + " status:" + descriptor.getStatus()); + if (DEBUG) { + // Show full stack trace if debugging + Log.e(TAG, "Exception parsing USB descriptors.", ex); + } + StackTraceElement[] stackElems = ex.getStackTrace(); + if (stackElems.length > 0) { + Log.i(TAG, " class:" + stackElems[0].getClassName() + + " @ " + stackElems[0].getLineNumber()); + } + if (stackElems.length > 1) { + Log.i(TAG, " class:" + stackElems[1].getClassName() + + " @ " + stackElems[1].getLineNumber()); + } + + // Finish up descriptor.setStatus(UsbDescriptor.STATUS_PARSE_EXCEPTION); } finally { mDescriptors.add(descriptor); diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java index 3f0aeb54f132..0c2f1f325793 100644 --- a/telephony/java/android/telephony/CellIdentity.java +++ b/telephony/java/android/telephony/CellIdentity.java @@ -69,8 +69,8 @@ public abstract class CellIdentity implements Parcelable { protected String mAlphaShort; /** @hide */ - protected CellIdentity(String tag, int type, String mcc, String mnc, String alphal, - String alphas) { + protected CellIdentity(@Nullable String tag, int type, @Nullable String mcc, + @Nullable String mnc, @Nullable String alphal, @Nullable String alphas) { mTag = tag; mType = type; diff --git a/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java index 1a6bf33cec71..e220b07d703a 100644 --- a/telephony/java/android/telephony/CellIdentityCdma.java +++ b/telephony/java/android/telephony/CellIdentityCdma.java @@ -17,6 +17,7 @@ package android.telephony; import android.annotation.NonNull; +import android.annotation.Nullable; import android.os.Parcel; import android.telephony.cdma.CdmaCellLocation; @@ -90,8 +91,8 @@ public final class CellIdentityCdma extends CellIdentity { * * @hide */ - public CellIdentityCdma( - int nid, int sid, int bid, int lon, int lat, String alphal, String alphas) { + public CellIdentityCdma(int nid, int sid, int bid, int lon, int lat, + @Nullable String alphal, @Nullable String alphas) { super(TAG, CellInfo.TYPE_CDMA, null, null, alphal, alphas); mNetworkId = inRangeOrUnavailable(nid, 0, NETWORK_ID_MAX); mSystemId = inRangeOrUnavailable(sid, 0, SYSTEM_ID_MAX); @@ -108,22 +109,22 @@ public final class CellIdentityCdma extends CellIdentity { } /** @hide */ - public CellIdentityCdma(android.hardware.radio.V1_0.CellIdentityCdma cid) { + public CellIdentityCdma(@NonNull android.hardware.radio.V1_0.CellIdentityCdma cid) { this(cid.networkId, cid.systemId, cid.baseStationId, cid.longitude, cid.latitude, "", ""); } /** @hide */ - public CellIdentityCdma(android.hardware.radio.V1_2.CellIdentityCdma cid) { + public CellIdentityCdma(@NonNull android.hardware.radio.V1_2.CellIdentityCdma cid) { this(cid.base.networkId, cid.base.systemId, cid.base.baseStationId, cid.base.longitude, cid.base.latitude, cid.operatorNames.alphaLong, cid.operatorNames.alphaShort); } - private CellIdentityCdma(CellIdentityCdma cid) { + private CellIdentityCdma(@NonNull CellIdentityCdma cid) { this(cid.mNetworkId, cid.mSystemId, cid.mBasestationId, cid.mLongitude, cid.mLatitude, cid.mAlphaLong, cid.mAlphaShort); } - CellIdentityCdma copy() { + @NonNull CellIdentityCdma copy() { return new CellIdentityCdma(this); } diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java index dc73cbf735b0..9f2537c7ed10 100644 --- a/telephony/java/android/telephony/CellIdentityGsm.java +++ b/telephony/java/android/telephony/CellIdentityGsm.java @@ -23,6 +23,7 @@ import android.os.Parcel; import android.telephony.gsm.GsmCellLocation; import android.text.TextUtils; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; @@ -78,26 +79,31 @@ public final class CellIdentityGsm extends CellIdentity { * * @hide */ - public CellIdentityGsm(int lac, int cid, int arfcn, int bsic, String mccStr, - String mncStr, String alphal, String alphas, - List<String> additionalPlmns) { + public CellIdentityGsm(int lac, int cid, int arfcn, int bsic, @Nullable String mccStr, + @Nullable String mncStr, @Nullable String alphal, @Nullable String alphas, + @NonNull List<String> additionalPlmns) { super(TAG, CellInfo.TYPE_GSM, mccStr, mncStr, alphal, alphas); mLac = inRangeOrUnavailable(lac, 0, MAX_LAC); mCid = inRangeOrUnavailable(cid, 0, MAX_CID); mArfcn = inRangeOrUnavailable(arfcn, 0, MAX_ARFCN); mBsic = inRangeOrUnavailable(bsic, 0, MAX_BSIC); - mAdditionalPlmns = additionalPlmns; + mAdditionalPlmns = new ArrayList<>(additionalPlmns.size()); + for (String plmn : additionalPlmns) { + if (isValidPlmn(plmn)) { + mAdditionalPlmns.add(plmn); + } + } } /** @hide */ - public CellIdentityGsm(android.hardware.radio.V1_0.CellIdentityGsm cid) { + public CellIdentityGsm(@NonNull android.hardware.radio.V1_0.CellIdentityGsm cid) { this(cid.lac, cid.cid, cid.arfcn, cid.bsic == (byte) 0xFF ? CellInfo.UNAVAILABLE : cid.bsic, cid.mcc, cid.mnc, "", "", Collections.emptyList()); } /** @hide */ - public CellIdentityGsm(android.hardware.radio.V1_2.CellIdentityGsm cid) { + public CellIdentityGsm(@NonNull android.hardware.radio.V1_2.CellIdentityGsm cid) { this(cid.base.lac, cid.base.cid, cid.base.arfcn, cid.base.bsic == (byte) 0xFF ? CellInfo.UNAVAILABLE : cid.base.bsic, cid.base.mcc, cid.base.mnc, cid.operatorNames.alphaLong, cid.operatorNames.alphaShort, @@ -105,7 +111,7 @@ public final class CellIdentityGsm extends CellIdentity { } /** @hide */ - public CellIdentityGsm(android.hardware.radio.V1_5.CellIdentityGsm cid) { + public CellIdentityGsm(@NonNull android.hardware.radio.V1_5.CellIdentityGsm cid) { this(cid.base.base.lac, cid.base.base.cid, cid.base.base.arfcn, cid.base.base.bsic == (byte) 0xFF ? CellInfo.UNAVAILABLE : cid.base.base.bsic, cid.base.base.mcc, @@ -113,12 +119,12 @@ public final class CellIdentityGsm extends CellIdentity { cid.base.operatorNames.alphaShort, cid.additionalPlmns); } - private CellIdentityGsm(CellIdentityGsm cid) { + private CellIdentityGsm(@NonNull CellIdentityGsm cid) { this(cid.mLac, cid.mCid, cid.mArfcn, cid.mBsic, cid.mMccStr, cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort, cid.mAdditionalPlmns); } - CellIdentityGsm copy() { + @NonNull CellIdentityGsm copy() { return new CellIdentityGsm(this); } diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java index cf8fe6a3c345..a194ae35216c 100644 --- a/telephony/java/android/telephony/CellIdentityLte.java +++ b/telephony/java/android/telephony/CellIdentityLte.java @@ -24,6 +24,7 @@ import android.os.Parcel; import android.telephony.gsm.GsmCellLocation; import android.text.TextUtils; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; @@ -104,34 +105,40 @@ public final class CellIdentityLte extends CellIdentity { * * @hide */ - public CellIdentityLte(int ci, int pci, int tac, int earfcn, int bandwidth, String mccStr, - String mncStr, String alphal, String alphas, List<String> additionalPlmns, - ClosedSubscriberGroupInfo csgInfo) { + public CellIdentityLte(int ci, int pci, int tac, int earfcn, int bandwidth, + @Nullable String mccStr, @Nullable String mncStr, @Nullable String alphal, + @Nullable String alphas, @NonNull List<String> additionalPlmns, + @Nullable ClosedSubscriberGroupInfo csgInfo) { super(TAG, CellInfo.TYPE_LTE, mccStr, mncStr, alphal, alphas); mCi = inRangeOrUnavailable(ci, 0, MAX_CI); mPci = inRangeOrUnavailable(pci, 0, MAX_PCI); mTac = inRangeOrUnavailable(tac, 0, MAX_TAC); mEarfcn = inRangeOrUnavailable(earfcn, 0, MAX_EARFCN); mBandwidth = inRangeOrUnavailable(bandwidth, 0, MAX_BANDWIDTH); - mAdditionalPlmns = additionalPlmns; + mAdditionalPlmns = new ArrayList<>(additionalPlmns.size()); + for (String plmn : additionalPlmns) { + if (isValidPlmn(plmn)) { + mAdditionalPlmns.add(plmn); + } + } mCsgInfo = csgInfo; } /** @hide */ - public CellIdentityLte(android.hardware.radio.V1_0.CellIdentityLte cid) { + public CellIdentityLte(@NonNull android.hardware.radio.V1_0.CellIdentityLte cid) { this(cid.ci, cid.pci, cid.tac, cid.earfcn, CellInfo.UNAVAILABLE, cid.mcc, cid.mnc, "", "", Collections.emptyList(), null); } /** @hide */ - public CellIdentityLte(android.hardware.radio.V1_2.CellIdentityLte cid) { + public CellIdentityLte(@NonNull android.hardware.radio.V1_2.CellIdentityLte cid) { this(cid.base.ci, cid.base.pci, cid.base.tac, cid.base.earfcn, cid.bandwidth, cid.base.mcc, cid.base.mnc, cid.operatorNames.alphaLong, cid.operatorNames.alphaShort, Collections.emptyList(), null); } /** @hide */ - public CellIdentityLte(android.hardware.radio.V1_5.CellIdentityLte cid) { + public CellIdentityLte(@NonNull android.hardware.radio.V1_5.CellIdentityLte cid) { this(cid.base.base.ci, cid.base.base.pci, cid.base.base.tac, cid.base.base.earfcn, cid.base.bandwidth, cid.base.base.mcc, cid.base.base.mnc, cid.base.operatorNames.alphaLong, cid.base.operatorNames.alphaShort, @@ -139,7 +146,7 @@ public final class CellIdentityLte extends CellIdentity { ? new ClosedSubscriberGroupInfo(cid.optionalCsgInfo.csgInfo()) : null); } - private CellIdentityLte(CellIdentityLte cid) { + private CellIdentityLte(@NonNull CellIdentityLte cid) { this(cid.mCi, cid.mPci, cid.mTac, cid.mEarfcn, cid.mBandwidth, cid.mMccStr, cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort, cid.mAdditionalPlmns, cid.mCsgInfo); } @@ -152,7 +159,7 @@ public final class CellIdentityLte extends CellIdentity { mMccStr, mMncStr, mAlphaLong, mAlphaShort, mAdditionalPlmns, null); } - CellIdentityLte copy() { + @NonNull CellIdentityLte copy() { return new CellIdentityLte(this); } diff --git a/telephony/java/android/telephony/CellIdentityNr.java b/telephony/java/android/telephony/CellIdentityNr.java index d4f181fc735a..a0ef5aa2feae 100644 --- a/telephony/java/android/telephony/CellIdentityNr.java +++ b/telephony/java/android/telephony/CellIdentityNr.java @@ -64,26 +64,32 @@ public final class CellIdentityNr extends CellIdentity { * @hide */ public CellIdentityNr(int pci, int tac, int nrArfcn, @NgranBand List<Integer> bands, - String mccStr, String mncStr, long nci, String alphal, String alphas, - List<String> additionalPlmns) { + @Nullable String mccStr, @Nullable String mncStr, long nci, + @Nullable String alphal, @Nullable String alphas, + @NonNull List<String> additionalPlmns) { super(TAG, CellInfo.TYPE_NR, mccStr, mncStr, alphal, alphas); mPci = inRangeOrUnavailable(pci, 0, MAX_PCI); mTac = inRangeOrUnavailable(tac, 0, MAX_TAC); mNrArfcn = inRangeOrUnavailable(nrArfcn, 0, MAX_NRARFCN); mBands = new ArrayList<>(bands); mNci = inRangeOrUnavailable(nci, 0, MAX_NCI); - mAdditionalPlmns = new ArrayList<>(additionalPlmns); + mAdditionalPlmns = new ArrayList<>(additionalPlmns.size()); + for (String plmn : additionalPlmns) { + if (isValidPlmn(plmn)) { + mAdditionalPlmns.add(plmn); + } + } } /** @hide */ - public CellIdentityNr(android.hardware.radio.V1_4.CellIdentityNr cid) { + public CellIdentityNr(@NonNull android.hardware.radio.V1_4.CellIdentityNr cid) { this(cid.pci, cid.tac, cid.nrarfcn, Collections.emptyList(), cid.mcc, cid.mnc, cid.nci, cid.operatorNames.alphaLong, cid.operatorNames.alphaShort, Collections.emptyList()); } /** @hide */ - public CellIdentityNr(android.hardware.radio.V1_5.CellIdentityNr cid) { + public CellIdentityNr(@NonNull android.hardware.radio.V1_5.CellIdentityNr cid) { this(cid.base.pci, cid.base.tac, cid.base.nrarfcn, cid.bands, cid.base.mcc, cid.base.mnc, cid.base.nci, cid.base.operatorNames.alphaLong, cid.base.operatorNames.alphaShort, cid.additionalPlmns); diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java index 2ff351c17e9a..531487a313d9 100644 --- a/telephony/java/android/telephony/CellIdentityTdscdma.java +++ b/telephony/java/android/telephony/CellIdentityTdscdma.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.os.Parcel; import android.telephony.gsm.GsmCellLocation; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; @@ -82,39 +83,44 @@ public final class CellIdentityTdscdma extends CellIdentity { * * @hide */ - public CellIdentityTdscdma(String mcc, String mnc, int lac, int cid, int cpid, int uarfcn, - String alphal, String alphas, @NonNull List<String> additionalPlmns, - ClosedSubscriberGroupInfo csgInfo) { + public CellIdentityTdscdma(@Nullable String mcc, @Nullable String mnc, int lac, int cid, + int cpid, int uarfcn, @Nullable String alphal, @Nullable String alphas, + @NonNull List<String> additionalPlmns, @Nullable ClosedSubscriberGroupInfo csgInfo) { super(TAG, CellInfo.TYPE_TDSCDMA, mcc, mnc, alphal, alphas); mLac = inRangeOrUnavailable(lac, 0, MAX_LAC); mCid = inRangeOrUnavailable(cid, 0, MAX_CID); mCpid = inRangeOrUnavailable(cpid, 0, MAX_CPID); mUarfcn = inRangeOrUnavailable(uarfcn, 0, MAX_UARFCN); - mAdditionalPlmns = additionalPlmns; + mAdditionalPlmns = new ArrayList<>(additionalPlmns.size()); + for (String plmn : additionalPlmns) { + if (isValidPlmn(plmn)) { + mAdditionalPlmns.add(plmn); + } + } mCsgInfo = csgInfo; } - private CellIdentityTdscdma(CellIdentityTdscdma cid) { + private CellIdentityTdscdma(@NonNull CellIdentityTdscdma cid) { this(cid.mMccStr, cid.mMncStr, cid.mLac, cid.mCid, cid.mCpid, cid.mUarfcn, cid.mAlphaLong, cid.mAlphaShort, cid.mAdditionalPlmns, cid.mCsgInfo); } /** @hide */ - public CellIdentityTdscdma(android.hardware.radio.V1_0.CellIdentityTdscdma cid) { + public CellIdentityTdscdma(@NonNull android.hardware.radio.V1_0.CellIdentityTdscdma cid) { this(cid.mcc, cid.mnc, cid.lac, cid.cid, cid.cpid, CellInfo.UNAVAILABLE, "", "", Collections.emptyList(), null); } /** @hide */ - public CellIdentityTdscdma(android.hardware.radio.V1_2.CellIdentityTdscdma cid) { + public CellIdentityTdscdma(@NonNull android.hardware.radio.V1_2.CellIdentityTdscdma cid) { this(cid.base.mcc, cid.base.mnc, cid.base.lac, cid.base.cid, cid.base.cpid, cid.uarfcn, cid.operatorNames.alphaLong, cid.operatorNames.alphaShort, Collections.emptyList(), null); } /** @hide */ - public CellIdentityTdscdma(android.hardware.radio.V1_5.CellIdentityTdscdma cid) { + public CellIdentityTdscdma(@NonNull android.hardware.radio.V1_5.CellIdentityTdscdma cid) { this(cid.base.base.mcc, cid.base.base.mnc, cid.base.base.lac, cid.base.base.cid, cid.base.base.cpid, cid.base.uarfcn, cid.base.operatorNames.alphaLong, cid.base.operatorNames.alphaShort, @@ -130,7 +136,7 @@ public final class CellIdentityTdscdma extends CellIdentity { mAdditionalPlmns, null); } - CellIdentityTdscdma copy() { + @NonNull CellIdentityTdscdma copy() { return new CellIdentityTdscdma(this); } diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java index 9be42a17677b..15e491b66575 100644 --- a/telephony/java/android/telephony/CellIdentityWcdma.java +++ b/telephony/java/android/telephony/CellIdentityWcdma.java @@ -23,6 +23,7 @@ import android.os.Parcel; import android.telephony.gsm.GsmCellLocation; import android.text.TextUtils; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; @@ -83,34 +84,38 @@ public final class CellIdentityWcdma extends CellIdentity { * * @hide */ - public CellIdentityWcdma (int lac, int cid, int psc, int uarfcn, - String mccStr, String mncStr, String alphal, String alphas, - @NonNull List<String> additionalPlmns, - @Nullable ClosedSubscriberGroupInfo csgInfo) { + public CellIdentityWcdma(int lac, int cid, int psc, int uarfcn, @Nullable String mccStr, + @Nullable String mncStr, @Nullable String alphal, @Nullable String alphas, + @NonNull List<String> additionalPlmns, @Nullable ClosedSubscriberGroupInfo csgInfo) { super(TAG, CellInfo.TYPE_WCDMA, mccStr, mncStr, alphal, alphas); mLac = inRangeOrUnavailable(lac, 0, MAX_LAC); mCid = inRangeOrUnavailable(cid, 0, MAX_CID); mPsc = inRangeOrUnavailable(psc, 0, MAX_PSC); mUarfcn = inRangeOrUnavailable(uarfcn, 0, MAX_UARFCN); - mAdditionalPlmns = additionalPlmns; + mAdditionalPlmns = new ArrayList<>(additionalPlmns.size()); + for (String plmn : additionalPlmns) { + if (isValidPlmn(plmn)) { + mAdditionalPlmns.add(plmn); + } + } mCsgInfo = csgInfo; } /** @hide */ - public CellIdentityWcdma(android.hardware.radio.V1_0.CellIdentityWcdma cid) { + public CellIdentityWcdma(@NonNull android.hardware.radio.V1_0.CellIdentityWcdma cid) { this(cid.lac, cid.cid, cid.psc, cid.uarfcn, cid.mcc, cid.mnc, "", "", Collections.emptyList(), null); } /** @hide */ - public CellIdentityWcdma(android.hardware.radio.V1_2.CellIdentityWcdma cid) { + public CellIdentityWcdma(@NonNull android.hardware.radio.V1_2.CellIdentityWcdma cid) { this(cid.base.lac, cid.base.cid, cid.base.psc, cid.base.uarfcn, cid.base.mcc, cid.base.mnc, cid.operatorNames.alphaLong, cid.operatorNames.alphaShort, Collections.emptyList(), null); } /** @hide */ - public CellIdentityWcdma(android.hardware.radio.V1_5.CellIdentityWcdma cid) { + public CellIdentityWcdma(@NonNull android.hardware.radio.V1_5.CellIdentityWcdma cid) { this(cid.base.base.lac, cid.base.base.cid, cid.base.base.psc, cid.base.base.uarfcn, cid.base.base.mcc, cid.base.base.mnc, cid.base.operatorNames.alphaLong, cid.base.operatorNames.alphaShort, cid.additionalPlmns, @@ -118,7 +123,7 @@ public final class CellIdentityWcdma extends CellIdentity { ? new ClosedSubscriberGroupInfo(cid.optionalCsgInfo.csgInfo()) : null); } - private CellIdentityWcdma(CellIdentityWcdma cid) { + private CellIdentityWcdma(@NonNull CellIdentityWcdma cid) { this(cid.mLac, cid.mCid, cid.mPsc, cid.mUarfcn, cid.mMccStr, cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort, cid.mAdditionalPlmns, cid.mCsgInfo); } @@ -131,7 +136,7 @@ public final class CellIdentityWcdma extends CellIdentity { mAlphaLong, mAlphaShort, mAdditionalPlmns, null); } - CellIdentityWcdma copy() { + @NonNull CellIdentityWcdma copy() { return new CellIdentityWcdma(this); } diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index 5cd7cf8fae8a..8e83c4c11992 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -2543,7 +2543,7 @@ public final class SmsManager { MmsManager m = (MmsManager) context.getSystemService(Context.MMS_SERVICE); if (m != null) { m.sendMultimediaMessage(getSubscriptionId(), contentUri, locationUrl, configOverrides, - sentIntent); + sentIntent, 0L /* messageId */); } } @@ -2581,7 +2581,7 @@ public final class SmsManager { MmsManager m = (MmsManager) context.getSystemService(Context.MMS_SERVICE); if (m != null) { m.downloadMultimediaMessage(getSubscriptionId(), locationUrl, contentUri, - configOverrides, downloadedIntent); + configOverrides, downloadedIntent, 0L /* messageId */); } } diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java index 80491cd98bc9..0fdcbc52bffa 100644 --- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java +++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java @@ -584,6 +584,25 @@ public class StagedRollbackTest { assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1); } + @Test + public void testRollbackApexDataDirectories_Phase1() throws Exception { + int sessionId = Install.single(TEST_APEX_WITH_APK_V2).setStaged().setEnableRollback() + .commit(); + InstallUtils.waitForSessionReady(sessionId); + } + + @Test + public void testRollbackApexDataDirectories_Phase2() throws Exception { + RollbackInfo available = RollbackUtils.getAvailableRollback(APK_IN_APEX_TESTAPEX_NAME); + + RollbackUtils.rollback(available.getRollbackId(), TEST_APEX_WITH_APK_V2); + RollbackInfo committed = RollbackUtils.getCommittedRollbackById(available.getRollbackId()); + + // Note: The app is not rolled back until after the rollback is staged + // and the device has been rebooted. + InstallUtils.waitForSessionReady(committed.getCommittedSessionId()); + } + private static void runShellCommand(String cmd) { ParcelFileDescriptor pfd = InstrumentationRegistry.getInstrumentation().getUiAutomation() .executeShellCommand(cmd); diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java index 672cbb084dae..ce2f7c50e581 100644 --- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java +++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java @@ -16,6 +16,8 @@ package com.android.tests.rollback.host; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; import static org.testng.Assert.assertThrows; @@ -53,6 +55,17 @@ public class StagedRollbackTest extends BaseHostJUnit4Test { private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test"; + private static final String TEST_SUBDIR = "/subdir/"; + + private static final String TEST_FILENAME_1 = "test_file.txt"; + private static final String TEST_STRING_1 = "hello this is a test"; + private static final String TEST_FILENAME_2 = "another_file.txt"; + private static final String TEST_STRING_2 = "this is a different file"; + private static final String TEST_FILENAME_3 = "also.xyz"; + private static final String TEST_STRING_3 = "also\n a\n test\n string"; + private static final String TEST_FILENAME_4 = "one_more.test"; + private static final String TEST_STRING_4 = "once more unto the test"; + @Before public void setUp() throws Exception { if (!getDevice().isAdbRoot()) { @@ -77,6 +90,10 @@ public class StagedRollbackTest extends BaseHostJUnit4Test { getDevice().executeShellCommand( "rm -f /system/apex/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex " + "/data/apex/active/" + APK_IN_APEX_TESTAPEX_NAME + "*.apex"); + getDevice().executeShellCommand( + "rm -rf " + apexDataDirDeSys(APK_IN_APEX_TESTAPEX_NAME) + "*"); + getDevice().executeShellCommand( + "rm -rf " + apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + "*"); getDevice().reboot(); } @@ -245,15 +262,7 @@ public class StagedRollbackTest extends BaseHostJUnit4Test { @Test public void testRollbackApexWithApk() throws Exception { getDevice().uninstallPackage("com.android.cts.install.lib.testapp.A"); - CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild()); - final String fileName = APK_IN_APEX_TESTAPEX_NAME + "_v1.apex"; - final File apex = buildHelper.getTestFile(fileName); - if (!getDevice().isAdbRoot()) { - getDevice().enableAdbRoot(); - } - getDevice().remountSystemWritable(); - assertTrue(getDevice().pushFile(apex, "/system/apex/" + fileName)); - getDevice().reboot(); + pushTestApex(); runPhase("testRollbackApexWithApk_Phase1"); getDevice().reboot(); runPhase("testRollbackApexWithApk_Phase2"); @@ -267,15 +276,7 @@ public class StagedRollbackTest extends BaseHostJUnit4Test { @Test public void testRollbackApexWithApkCrashing() throws Exception { getDevice().uninstallPackage("com.android.cts.install.lib.testapp.A"); - CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild()); - final String fileName = APK_IN_APEX_TESTAPEX_NAME + "_v1.apex"; - final File apex = buildHelper.getTestFile(fileName); - if (!getDevice().isAdbRoot()) { - getDevice().enableAdbRoot(); - } - getDevice().remountSystemWritable(); - assertTrue(getDevice().pushFile(apex, "/system/apex/" + fileName)); - getDevice().reboot(); + pushTestApex(); // Install an apex with apk that crashes runPhase("testRollbackApexWithApkCrashing_Phase1"); @@ -289,6 +290,102 @@ public class StagedRollbackTest extends BaseHostJUnit4Test { runPhase("testRollbackApexWithApkCrashing_Phase3"); } + /** + * Tests that data in DE_sys apex data directory is restored when apex is rolled back. + */ + @Test + public void testRollbackApexDataDirectories_DeSys() throws Exception { + pushTestApex(); + + // Push files to apex data directory + String oldFilePath1 = apexDataDirDeSys(APK_IN_APEX_TESTAPEX_NAME) + "/" + TEST_FILENAME_1; + String oldFilePath2 = + apexDataDirDeSys(APK_IN_APEX_TESTAPEX_NAME) + TEST_SUBDIR + TEST_FILENAME_2; + assertTrue(getDevice().pushString(TEST_STRING_1, oldFilePath1)); + assertTrue(getDevice().pushString(TEST_STRING_2, oldFilePath2)); + + // Install new version of the APEX with rollback enabled + runPhase("testRollbackApexDataDirectories_Phase1"); + getDevice().reboot(); + + // Replace files in data directory + getDevice().deleteFile(oldFilePath1); + getDevice().deleteFile(oldFilePath2); + String newFilePath3 = apexDataDirDeSys(APK_IN_APEX_TESTAPEX_NAME) + "/" + TEST_FILENAME_3; + String newFilePath4 = + apexDataDirDeSys(APK_IN_APEX_TESTAPEX_NAME) + TEST_SUBDIR + TEST_FILENAME_4; + assertTrue(getDevice().pushString(TEST_STRING_3, newFilePath3)); + assertTrue(getDevice().pushString(TEST_STRING_4, newFilePath4)); + + // Roll back the APEX + runPhase("testRollbackApexDataDirectories_Phase2"); + getDevice().reboot(); + + // Verify that old files have been restored and new files are gone + assertEquals(TEST_STRING_1, getDevice().pullFileContents(oldFilePath1)); + assertEquals(TEST_STRING_2, getDevice().pullFileContents(oldFilePath2)); + assertNull(getDevice().pullFile(newFilePath3)); + assertNull(getDevice().pullFile(newFilePath4)); + } + + /** + * Tests that data in CE apex data directory is restored when apex is rolled back. + */ + @Test + public void testRollbackApexDataDirectories_Ce() throws Exception { + pushTestApex(); + + // Push files to apex data directory + String oldFilePath1 = apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + "/" + TEST_FILENAME_1; + String oldFilePath2 = + apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + TEST_SUBDIR + TEST_FILENAME_2; + assertTrue(getDevice().pushString(TEST_STRING_1, oldFilePath1)); + assertTrue(getDevice().pushString(TEST_STRING_2, oldFilePath2)); + + // Install new version of the APEX with rollback enabled + runPhase("testRollbackApexDataDirectories_Phase1"); + getDevice().reboot(); + + // Replace files in data directory + getDevice().deleteFile(oldFilePath1); + getDevice().deleteFile(oldFilePath2); + String newFilePath3 = apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + "/" + TEST_FILENAME_3; + String newFilePath4 = + apexDataDirCe(APK_IN_APEX_TESTAPEX_NAME, 0) + TEST_SUBDIR + TEST_FILENAME_4; + assertTrue(getDevice().pushString(TEST_STRING_3, newFilePath3)); + assertTrue(getDevice().pushString(TEST_STRING_4, newFilePath4)); + + // Roll back the APEX + runPhase("testRollbackApexDataDirectories_Phase2"); + getDevice().reboot(); + + // Verify that old files have been restored and new files are gone + assertEquals(TEST_STRING_1, getDevice().pullFileContents(oldFilePath1)); + assertEquals(TEST_STRING_2, getDevice().pullFileContents(oldFilePath2)); + assertNull(getDevice().pullFile(newFilePath3)); + assertNull(getDevice().pullFile(newFilePath4)); + } + + private void pushTestApex() throws Exception { + CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild()); + final String fileName = APK_IN_APEX_TESTAPEX_NAME + "_v1.apex"; + final File apex = buildHelper.getTestFile(fileName); + if (!getDevice().isAdbRoot()) { + getDevice().enableAdbRoot(); + } + getDevice().remountSystemWritable(); + assertTrue(getDevice().pushFile(apex, "/system/apex/" + fileName)); + getDevice().reboot(); + } + + private static String apexDataDirDeSys(String apexName) { + return String.format("/data/misc/apexdata/%s", apexName); + } + + private static String apexDataDirCe(String apexName, int userId) { + return String.format("/data/misc_ce/%d/apexdata/%s", userId, apexName); + } + private void crashProcess(String processName, int numberOfCrashes) throws Exception { String pid = ""; String lastPid = "invalid"; diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index 31b3a5064932..1f1c0c12cf21 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -123,8 +123,6 @@ interface IWifiManager boolean isWifiStandardSupported(int standard); - boolean needs5GHzToAnyApBandConversion(); - DhcpInfo getDhcpInfo(); boolean isScanAlwaysAvailable(); diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java index f8d48c5403f7..7c031eaaeaf4 100644 --- a/wifi/java/android/net/wifi/WifiInfo.java +++ b/wifi/java/android/net/wifi/WifiInfo.java @@ -889,6 +889,13 @@ public class WifiInfo implements Parcelable { */ @Nullable @SystemApi + public static String sanitizeSsid(@Nullable String string) { + return removeDoubleQuotes(string); + } + + /** @hide */ + @UnsupportedAppUsage + @Nullable public static String removeDoubleQuotes(@Nullable String string) { if (string == null) return null; final int length = string.length(); diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 9a251062cd9e..76f97164032c 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -2802,29 +2802,6 @@ public class WifiManager { } /** - * Check if the device is dual mode capable i.e. supports concurrent STA + Soft AP. - * - * If the device is dual mode capable, it may require conversion of the user's Soft AP band - * selection {@link SoftApConfiguration#mBand} from {@link SoftApConfiguration#BAND_5GHZ} to - * include also {@link SoftApConfiguration#BAND_2GHZ}, since if the device is connected to a - * 5GHz DFS channel as a STA, it may be unable to honor a request to start Soft AP on the same - * DFS channel. - * - * @return {@code true} if dual mode STA + AP is supported by this device, {@code false} - * otherwise. - * @hide - */ - @SystemApi - @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) - public boolean isDualModeSupported() { - try { - return mService.needs5GHzToAnyApBandConversion(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** * Return the DHCP-assigned addresses from the last successful DHCP request, * if any. * @return the DHCP information diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java index b46755349ad7..060c85cac209 100644 --- a/wifi/java/com/android/server/wifi/BaseWifiService.java +++ b/wifi/java/com/android/server/wifi/BaseWifiService.java @@ -38,6 +38,7 @@ import android.net.wifi.ScanResult; import android.net.wifi.SoftApConfiguration; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; import android.net.wifi.WifiNetworkSuggestion; import android.net.wifi.hotspot2.IProvisioningCallback; import android.net.wifi.hotspot2.OsuProvider; @@ -268,7 +269,8 @@ public class BaseWifiService extends IWifiManager.Stub { throw new UnsupportedOperationException(); } - @Override + /** @deprecated use {@link WifiManager#isStaApConcurrencySupported()} */ + @Deprecated public boolean needs5GHzToAnyApBandConversion() { throw new UnsupportedOperationException(); } diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java index 0c2876e340c1..a189d507a32a 100644 --- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java +++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java @@ -1928,16 +1928,6 @@ public class WifiManagerTest { } /** - * Test behavior of {@link WifiManager#isDualModeSupported()} ()} - */ - @Test - public void testIsDualModeSupported() throws Exception { - when(mWifiService.needs5GHzToAnyApBandConversion()).thenReturn(true); - assertTrue(mWifiManager.isDualModeSupported()); - verify(mWifiService).needs5GHzToAnyApBandConversion(); - } - - /** * Test behavior of {@link WifiManager#is5GHzBandSupported()} */ @Test |