diff options
108 files changed, 3110 insertions, 1076 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index 104cf508939a..0ba3fd8a53cc 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -25315,6 +25315,41 @@ package android.net { method public void onTetheringStarted(); } + public final class ConnectivityMetricsEvent implements android.os.Parcelable { + ctor public ConnectivityMetricsEvent(long, int, int, android.os.Parcelable); + method public int describeContents(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.net.ConnectivityMetricsEvent> CREATOR; + field public final int componentTag; + field public final android.os.Parcelable data; + field public final int eventTag; + field public final long timestamp; + } + + public static final class ConnectivityMetricsEvent.Reference implements android.os.Parcelable { + ctor public ConnectivityMetricsEvent.Reference(long); + method public int describeContents(); + method public long getValue(); + method public void readFromParcel(android.os.Parcel); + method public void setValue(long); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.net.ConnectivityMetricsEvent.Reference> CREATOR; + } + + public class ConnectivityMetricsLogger { + ctor public ConnectivityMetricsLogger(); + method public void logEvent(long, int, int, android.os.Parcelable); + field public static final int COMPONENT_TAG_BLUETOOTH = 1; // 0x1 + field public static final int COMPONENT_TAG_CONNECTIVITY = 0; // 0x0 + field public static final int COMPONENT_TAG_TELECOM = 3; // 0x3 + field public static final int COMPONENT_TAG_TELEPHONY = 4; // 0x4 + field public static final int COMPONENT_TAG_WIFI = 2; // 0x2 + field public static final java.lang.String CONNECTIVITY_METRICS_LOGGER_SERVICE = "connectivity_metrics_logger"; + field public static final java.lang.String DATA_KEY_EVENTS_COUNT = "count"; + field public static final int NUMBER_OF_COMPONENTS = 5; // 0x5 + field public static final int TAG_SKIPPED_EVENTS = -1; // 0xffffffff + } + public class Credentials { ctor public Credentials(int, int, int); method public int getGid(); @@ -26387,9 +26422,11 @@ package android.net.wifi { field public int bwSupported; field public boolean lciSupported; field public boolean lcrSupported; + field public int mcVersion; field public boolean oneSidedRttSupported; field public int preambleSupported; field public boolean responderSupported; + field public boolean secureRttSupported; field public deprecated boolean supportedPeerType; field public deprecated boolean supportedType; field public boolean twoSided11McRttSupported; diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 7bf03deee669..a82b950bda87 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -2578,9 +2578,10 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } - case START_LOCK_TASK_BY_CURRENT_TRANSACTION: { + case START_SYSTEM_LOCK_TASK_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); - startLockTaskModeOnCurrent(); + int taskId = data.readInt(); + startSystemLockTaskMode(taskId); reply.writeNoException(); return true; } @@ -2592,9 +2593,9 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } - case STOP_LOCK_TASK_BY_CURRENT_TRANSACTION: { + case STOP_SYSTEM_LOCK_TASK_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); - stopLockTaskModeOnCurrent(); + stopSystemLockTaskMode(); reply.writeNoException(); return true; } @@ -6386,11 +6387,12 @@ class ActivityManagerProxy implements IActivityManager } @Override - public void startLockTaskModeOnCurrent() throws RemoteException { + public void startSystemLockTaskMode(int taskId) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); - mRemote.transact(START_LOCK_TASK_BY_CURRENT_TRANSACTION, data, reply, 0); + data.writeInt(taskId); + mRemote.transact(START_SYSTEM_LOCK_TASK_TRANSACTION, data, reply, 0); reply.readException(); data.recycle(); reply.recycle(); @@ -6408,11 +6410,11 @@ class ActivityManagerProxy implements IActivityManager } @Override - public void stopLockTaskModeOnCurrent() throws RemoteException { + public void stopSystemLockTaskMode() throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); - mRemote.transact(STOP_LOCK_TASK_BY_CURRENT_TRANSACTION, data, reply, 0); + mRemote.transact(STOP_SYSTEM_LOCK_TASK_TRANSACTION, data, reply, 0); reply.readException(); data.recycle(); reply.recycle(); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 6975116c6be3..1a4e98cc4d36 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -555,7 +555,7 @@ public interface IActivityManager extends IInterface { public int getActivityDisplayId(IBinder activityToken) throws RemoteException; - public void startLockTaskModeOnCurrent() throws RemoteException; + public void startSystemLockTaskMode(int taskId) throws RemoteException; public void startLockTaskMode(int taskId) throws RemoteException; @@ -563,7 +563,7 @@ public interface IActivityManager extends IInterface { public void stopLockTaskMode() throws RemoteException; - public void stopLockTaskModeOnCurrent() throws RemoteException; + public void stopSystemLockTaskMode() throws RemoteException; public boolean isInLockTaskMode() throws RemoteException; @@ -949,8 +949,8 @@ public interface IActivityManager extends IInterface { int START_VOICE_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+218; int GET_ACTIVITY_OPTIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+219; int GET_APP_TASKS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+220; - int START_LOCK_TASK_BY_CURRENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+221; - int STOP_LOCK_TASK_BY_CURRENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+222; + int START_SYSTEM_LOCK_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+221; + int STOP_SYSTEM_LOCK_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+222; int FINISH_VOICE_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+223; int IS_TOP_OF_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+224; int REQUEST_VISIBLE_BEHIND_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+225; diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 269089e3a262..7a18df6e4e44 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -1093,6 +1093,7 @@ public class DevicePolicyManager { * returned. */ public List<ComponentName> getActiveAdmins() { + throwIfParentInstance("getActiveAdmins"); return getActiveAdminsAsUser(myUserId()); } @@ -1149,6 +1150,7 @@ public class DevicePolicyManager { * @throws SecurityException if the caller is not in the owner application of {@code admin}. */ public void removeActiveAdmin(@NonNull ComponentName admin) { + throwIfParentInstance("removeActiveAdmin"); if (mService != null) { try { mService.removeActiveAdmin(admin, myUserId()); @@ -1169,6 +1171,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not an active administrator. */ public boolean hasGrantedPolicy(@NonNull ComponentName admin, int usesPolicy) { + throwIfParentInstance("hasGrantedPolicy"); if (mService != null) { try { return mService.hasGrantedPolicy(admin, usesPolicy, myUserId()); @@ -2216,9 +2219,7 @@ public class DevicePolicyManager { * that uses {@link DeviceAdminInfo#USES_POLICY_RESET_PASSWORD} */ public boolean resetPassword(String password, int flags) { - if (mParentInstance) { - throw new SecurityException("Reset password does not work across profiles."); - } + throwIfParentInstance("resetPassword"); if (mService != null) { try { return mService.resetPassword(password, flags); @@ -2355,6 +2356,7 @@ public class DevicePolicyManager { * that uses {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA} */ public void wipeData(int flags) { + throwIfParentInstance("wipeData"); if (mService != null) { try { mService.wipeData(flags); @@ -2388,6 +2390,7 @@ public class DevicePolicyManager { */ public ComponentName setGlobalProxy(@NonNull ComponentName admin, Proxy proxySpec, List<String> exclusionList ) { + throwIfParentInstance("setGlobalProxy"); if (proxySpec == null) { throw new NullPointerException(); } @@ -2453,6 +2456,7 @@ public class DevicePolicyManager { */ public void setRecommendedGlobalProxy(@NonNull ComponentName admin, @Nullable ProxyInfo proxyInfo) { + throwIfParentInstance("setRecommendedGlobalProxy"); if (mService != null) { try { mService.setRecommendedGlobalProxy(admin, proxyInfo); @@ -2603,6 +2607,7 @@ public class DevicePolicyManager { * {@link DeviceAdminInfo#USES_ENCRYPTED_STORAGE} */ public int setStorageEncryption(@NonNull ComponentName admin, boolean encrypt) { + throwIfParentInstance("setStorageEncryption"); if (mService != null) { try { return mService.setStorageEncryption(admin, encrypt); @@ -2623,6 +2628,7 @@ public class DevicePolicyManager { * @return true if the admin(s) are requesting encryption, false if not. */ public boolean getStorageEncryption(@Nullable ComponentName admin) { + throwIfParentInstance("getStorageEncryption"); if (mService != null) { try { return mService.getStorageEncryption(admin, myUserId()); @@ -2653,6 +2659,7 @@ public class DevicePolicyManager { * or {@link #ENCRYPTION_STATUS_ACTIVE}. */ public int getStorageEncryptionStatus() { + throwIfParentInstance("getStorageEncryptionStatus"); return getStorageEncryptionStatus(myUserId()); } @@ -2718,6 +2725,7 @@ public class DevicePolicyManager { * owner. */ public boolean installCaCert(@Nullable ComponentName admin, byte[] certBuffer) { + throwIfParentInstance("installCaCert"); if (mService != null) { try { return mService.installCaCert(admin, certBuffer); @@ -2738,6 +2746,7 @@ public class DevicePolicyManager { * owner. */ public void uninstallCaCert(@Nullable ComponentName admin, byte[] certBuffer) { + throwIfParentInstance("uninstallCaCert"); if (mService != null) { try { final String alias = getCaCertAlias(certBuffer); @@ -2763,6 +2772,7 @@ public class DevicePolicyManager { */ public List<byte[]> getInstalledCaCerts(@Nullable ComponentName admin) { List<byte[]> certs = new ArrayList<byte[]>(); + throwIfParentInstance("getInstalledCaCerts"); if (mService != null) { try { mService.enforceCanManageCaCerts(admin); @@ -2791,6 +2801,7 @@ public class DevicePolicyManager { * owner. */ public void uninstallAllUserCaCerts(@Nullable ComponentName admin) { + throwIfParentInstance("uninstallAllUserCaCerts"); if (mService != null) { try { mService.uninstallCaCerts(admin, new TrustedCertificateStore().userAliases() @@ -2811,6 +2822,7 @@ public class DevicePolicyManager { * owner. */ public boolean hasCaCertInstalled(@Nullable ComponentName admin, byte[] certBuffer) { + throwIfParentInstance("hasCaCertInstalled"); if (mService != null) { try { mService.enforceCanManageCaCerts(admin); @@ -2879,6 +2891,7 @@ public class DevicePolicyManager { */ public boolean installKeyPair(@Nullable ComponentName admin, @NonNull PrivateKey privKey, @NonNull Certificate[] certs, @NonNull String alias, boolean requestAccess) { + throwIfParentInstance("installKeyPair"); try { final byte[] pemCert = Credentials.convertToPem(certs[0]); byte[] pemChain = null; @@ -2911,6 +2924,7 @@ public class DevicePolicyManager { * owner. */ public boolean removeKeyPair(@Nullable ComponentName admin, @NonNull String alias) { + throwIfParentInstance("removeKeyPair"); try { return mService.removeKeyPair(admin, alias); } catch (RemoteException e) { @@ -2951,6 +2965,7 @@ public class DevicePolicyManager { */ public void setCertInstallerPackage(@NonNull ComponentName admin, @Nullable String installerPackage) throws SecurityException { + throwIfParentInstance("setCertInstallerPackage"); if (mService != null) { try { mService.setCertInstallerPackage(admin, installerPackage); @@ -2970,6 +2985,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device or a profile owner. */ public String getCertInstallerPackage(@NonNull ComponentName admin) throws SecurityException { + throwIfParentInstance("getCertInstallerPackage"); if (mService != null) { try { return mService.getCertInstallerPackage(admin); @@ -3000,6 +3016,7 @@ public class DevicePolicyManager { */ public void setAlwaysOnVpnPackage(@NonNull ComponentName admin, @Nullable String vpnPackage) throws NameNotFoundException, UnsupportedOperationException { + throwIfParentInstance("setAlwaysOnVpnPackage"); if (mService != null) { try { if (!mService.setAlwaysOnVpnPackage(admin, vpnPackage)) { @@ -3021,6 +3038,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device or a profile owner. */ public String getAlwaysOnVpnPackage(@NonNull ComponentName admin) { + throwIfParentInstance("getAlwaysOnVpnPackage"); if (mService != null) { try { return mService.getAlwaysOnVpnPackage(admin); @@ -3048,6 +3066,7 @@ public class DevicePolicyManager { * {@link DeviceAdminInfo#USES_POLICY_DISABLE_CAMERA}. */ public void setCameraDisabled(@NonNull ComponentName admin, boolean disabled) { + throwIfParentInstance("setCameraDisabled"); if (mService != null) { try { mService.setCameraDisabled(admin, disabled); @@ -3064,6 +3083,7 @@ public class DevicePolicyManager { * have disabled the camera */ public boolean getCameraDisabled(@Nullable ComponentName admin) { + throwIfParentInstance("getCameraDisabled"); return getCameraDisabled(admin, myUserId()); } @@ -3093,6 +3113,7 @@ public class DevicePolicyManager { * than the one managed by the device owner. */ public boolean requestBugreport(@NonNull ComponentName admin) { + throwIfParentInstance("requestBugreport"); if (mService != null) { try { return mService.requestBugreport(admin); @@ -3131,6 +3152,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device or profile owner. */ public void setScreenCaptureDisabled(@NonNull ComponentName admin, boolean disabled) { + throwIfParentInstance("setScreenCaptureDisabled"); if (mService != null) { try { mService.setScreenCaptureDisabled(admin, disabled); @@ -3147,6 +3169,7 @@ public class DevicePolicyManager { * have disabled screen capture. */ public boolean getScreenCaptureDisabled(@Nullable ComponentName admin) { + throwIfParentInstance("getScreenCaptureDisabled"); return getScreenCaptureDisabled(admin, myUserId()); } @@ -3176,6 +3199,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device owner. */ public void setAutoTimeRequired(@NonNull ComponentName admin, boolean required) { + throwIfParentInstance("setAutoTimeRequired"); if (mService != null) { try { mService.setAutoTimeRequired(admin, required); @@ -3189,6 +3213,7 @@ public class DevicePolicyManager { * @return true if auto time is required. */ public boolean getAutoTimeRequired() { + throwIfParentInstance("getAutoTimeRequired"); if (mService != null) { try { return mService.getAutoTimeRequired(); @@ -3215,6 +3240,7 @@ public class DevicePolicyManager { */ public void setForceEphemeralUsers( @NonNull ComponentName admin, boolean forceEphemeralUsers) { + throwIfParentInstance("setForceEphemeralUsers"); if (mService != null) { try { mService.setForceEphemeralUsers(admin, forceEphemeralUsers); @@ -3230,6 +3256,7 @@ public class DevicePolicyManager { * @hide */ public boolean getForceEphemeralUsers(@NonNull ComponentName admin) { + throwIfParentInstance("getForceEphemeralUsers"); if (mService != null) { try { return mService.getForceEphemeralUsers(admin); @@ -3517,6 +3544,7 @@ public class DevicePolicyManager { * @return whether or not the package is registered as the device owner app. */ public boolean isDeviceOwnerApp(String packageName) { + throwIfParentInstance("isDeviceOwnerApp"); return isDeviceOwnerAppOnCallingUser(packageName); } @@ -3614,6 +3642,7 @@ public class DevicePolicyManager { * does not own the current device owner component. */ public void clearDeviceOwnerApp(String packageName) { + throwIfParentInstance("clearDeviceOwnerApp"); if (mService != null) { try { mService.clearDeviceOwner(packageName); @@ -3632,6 +3661,7 @@ public class DevicePolicyManager { */ @SystemApi public String getDeviceOwner() { + throwIfParentInstance("getDeviceOwner"); final ComponentName name = getDeviceOwnerComponentOnCallingUser(); return name != null ? name.getPackageName() : null; } @@ -3657,6 +3687,7 @@ public class DevicePolicyManager { */ @SystemApi public String getDeviceOwnerNameOnAnyUser() { + throwIfParentInstance("getDeviceOwnerNameOnAnyUser"); if (mService != null) { try { return mService.getDeviceOwnerName(); @@ -3708,6 +3739,7 @@ public class DevicePolicyManager { @SystemApi public boolean setActiveProfileOwner(@NonNull ComponentName admin, @Deprecated String ownerName) throws IllegalArgumentException { + throwIfParentInstance("setActiveProfileOwner"); if (mService != null) { try { final int myUserId = myUserId(); @@ -3731,6 +3763,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not an active profile owner. */ public void clearProfileOwner(@NonNull ComponentName admin) { + throwIfParentInstance("clearProfileOwner"); if (mService != null) { try { mService.clearProfileOwner(admin); @@ -3804,6 +3837,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device owner. */ public void setDeviceOwnerLockScreenInfo(@NonNull ComponentName admin, CharSequence info) { + throwIfParentInstance("setDeviceOwnerLockScreenInfo"); if (mService != null) { try { mService.setDeviceOwnerLockScreenInfo(admin, info); @@ -3817,6 +3851,7 @@ public class DevicePolicyManager { * @return The device owner information. If it is not set returns {@code null}. */ public CharSequence getDeviceOwnerLockScreenInfo() { + throwIfParentInstance("getDeviceOwnerLockScreenInfo"); if (mService != null) { try { return mService.getDeviceOwnerLockScreenInfo(); @@ -3848,6 +3883,7 @@ public class DevicePolicyManager { */ public String[] setPackagesSuspended(@NonNull ComponentName admin, String[] packageNames, boolean suspended) { + throwIfParentInstance("setPackagesSuspended"); if (mService != null) { try { return mService.setPackagesSuspended(admin, packageNames, suspended); @@ -3870,6 +3906,7 @@ public class DevicePolicyManager { */ public boolean isPackageSuspended(@NonNull ComponentName admin, String packageName) throws NameNotFoundException { + throwIfParentInstance("isPackageSuspended"); if (mService != null) { try { return mService.isPackageSuspended(admin, packageName); @@ -3891,6 +3928,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a profile owner. */ public void setProfileEnabled(@NonNull ComponentName admin) { + throwIfParentInstance("setProfileEnabled"); if (mService != null) { try { mService.setProfileEnabled(admin); @@ -3912,6 +3950,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device or profile owner. */ public void setProfileName(@NonNull ComponentName admin, String profileName) { + throwIfParentInstance("setProfileName"); if (mService != null) { try { mService.setProfileName(admin, profileName); @@ -3930,6 +3969,7 @@ public class DevicePolicyManager { * @return Whether or not the package is registered as the profile owner. */ public boolean isProfileOwnerApp(String packageName) { + throwIfParentInstance("isProfileOwnerApp"); if (mService != null) { try { ComponentName profileOwner = mService.getProfileOwner(myUserId()); @@ -3950,6 +3990,7 @@ public class DevicePolicyManager { */ @SystemApi public ComponentName getProfileOwner() throws IllegalArgumentException { + throwIfParentInstance("getProfileOwner"); return getProfileOwnerAsUser(Process.myUserHandle().getIdentifier()); } @@ -3994,6 +4035,7 @@ public class DevicePolicyManager { */ @SystemApi public String getProfileOwnerNameAsUser(int userId) throws IllegalArgumentException { + throwIfParentInstance("getProfileOwnerNameAsUser"); if (mService != null) { try { return mService.getProfileOwnerName(userId); @@ -4024,6 +4066,7 @@ public class DevicePolicyManager { */ public void addPersistentPreferredActivity(@NonNull ComponentName admin, IntentFilter filter, @NonNull ComponentName activity) { + throwIfParentInstance("addPersistentPreferredActivity"); if (mService != null) { try { mService.addPersistentPreferredActivity(admin, filter, activity); @@ -4046,6 +4089,7 @@ public class DevicePolicyManager { */ public void clearPackagePersistentPreferredActivities(@NonNull ComponentName admin, String packageName) { + throwIfParentInstance("clearPackagePersistentPreferredActivities"); if (mService != null) { try { mService.clearPackagePersistentPreferredActivities(admin, packageName); @@ -4074,6 +4118,7 @@ public class DevicePolicyManager { */ public void setApplicationRestrictionsManagingPackage(@NonNull ComponentName admin, @Nullable String packageName) throws NameNotFoundException { + throwIfParentInstance("setApplicationRestrictionsManagingPackage"); if (mService != null) { try { if (!mService.setApplicationRestrictionsManagingPackage(admin, packageName)) { @@ -4095,6 +4140,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device or profile owner. */ public String getApplicationRestrictionsManagingPackage(@NonNull ComponentName admin) { + throwIfParentInstance("getApplicationRestrictionsManagingPackage"); if (mService != null) { try { return mService.getApplicationRestrictionsManagingPackage(admin); @@ -4114,6 +4160,7 @@ public class DevicePolicyManager { * that method. */ public boolean isCallerApplicationRestrictionsManagingPackage() { + throwIfParentInstance("isCallerApplicationRestrictionsManagingPackage"); if (mService != null) { try { return mService.isCallerApplicationRestrictionsManagingPackage(); @@ -4159,6 +4206,7 @@ public class DevicePolicyManager { */ public void setApplicationRestrictions(@Nullable ComponentName admin, String packageName, Bundle settings) { + throwIfParentInstance("setApplicationRestrictions"); if (mService != null) { try { mService.setApplicationRestrictions(admin, packageName, settings); @@ -4257,6 +4305,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device or profile owner. */ public void setCrossProfileCallerIdDisabled(@NonNull ComponentName admin, boolean disabled) { + throwIfParentInstance("setCrossProfileCallerIdDisabled"); if (mService != null) { try { mService.setCrossProfileCallerIdDisabled(admin, disabled); @@ -4277,6 +4326,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device or profile owner. */ public boolean getCrossProfileCallerIdDisabled(@NonNull ComponentName admin) { + throwIfParentInstance("getCrossProfileCallerIdDisabled"); if (mService != null) { try { return mService.getCrossProfileCallerIdDisabled(admin); @@ -4317,6 +4367,7 @@ public class DevicePolicyManager { */ public void setCrossProfileContactsSearchDisabled(@NonNull ComponentName admin, boolean disabled) { + throwIfParentInstance("setCrossProfileContactsSearchDisabled"); if (mService != null) { try { mService.setCrossProfileContactsSearchDisabled(admin, disabled); @@ -4337,6 +4388,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device or profile owner. */ public boolean getCrossProfileContactsSearchDisabled(@NonNull ComponentName admin) { + throwIfParentInstance("getCrossProfileContactsSearchDisabled"); if (mService != null) { try { return mService.getCrossProfileContactsSearchDisabled(admin); @@ -4407,6 +4459,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device or profile owner. */ public void setBluetoothContactSharingDisabled(@NonNull ComponentName admin, boolean disabled) { + throwIfParentInstance("setBluetoothContactSharingDisabled"); if (mService != null) { try { mService.setBluetoothContactSharingDisabled(admin, disabled); @@ -4429,6 +4482,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device or profile owner. */ public boolean getBluetoothContactSharingDisabled(@NonNull ComponentName admin) { + throwIfParentInstance("getBluetoothContactSharingDisabled"); if (mService != null) { try { return mService.getBluetoothContactSharingDisabled(admin); @@ -4472,6 +4526,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device or profile owner. */ public void addCrossProfileIntentFilter(@NonNull ComponentName admin, IntentFilter filter, int flags) { + throwIfParentInstance("addCrossProfileIntentFilter"); if (mService != null) { try { mService.addCrossProfileIntentFilter(admin, filter, flags); @@ -4490,6 +4545,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device or profile owner. */ public void clearCrossProfileIntentFilters(@NonNull ComponentName admin) { + throwIfParentInstance("clearCrossProfileIntentFilters"); if (mService != null) { try { mService.clearCrossProfileIntentFilters(admin); @@ -4519,6 +4575,7 @@ public class DevicePolicyManager { */ public boolean setPermittedAccessibilityServices(@NonNull ComponentName admin, List<String> packageNames) { + throwIfParentInstance("setPermittedAccessibilityServices"); if (mService != null) { try { return mService.setPermittedAccessibilityServices(admin, packageNames); @@ -4540,6 +4597,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device or profile owner. */ public List<String> getPermittedAccessibilityServices(@NonNull ComponentName admin) { + throwIfParentInstance("getPermittedAccessibilityServices"); if (mService != null) { try { return mService.getPermittedAccessibilityServices(admin); @@ -4587,6 +4645,7 @@ public class DevicePolicyManager { */ @SystemApi public List<String> getPermittedAccessibilityServices(int userId) { + throwIfParentInstance("getPermittedAccessibilityServices"); if (mService != null) { try { return mService.getPermittedAccessibilityServicesForUser(userId); @@ -4617,6 +4676,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device or profile owner. */ public boolean setPermittedInputMethods(@NonNull ComponentName admin, List<String> packageNames) { + throwIfParentInstance("setPermittedInputMethods"); if (mService != null) { try { return mService.setPermittedInputMethods(admin, packageNames); @@ -4639,6 +4699,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device or profile owner. */ public List<String> getPermittedInputMethods(@NonNull ComponentName admin) { + throwIfParentInstance("getPermittedInputMethods"); if (mService != null) { try { return mService.getPermittedInputMethods(admin); @@ -4684,6 +4745,7 @@ public class DevicePolicyManager { */ @SystemApi public List<String> getPermittedInputMethodsForCurrentUser() { + throwIfParentInstance("getPermittedInputMethodsForCurrentUser"); if (mService != null) { try { return mService.getPermittedInputMethodsForCurrentUser(); @@ -4704,6 +4766,7 @@ public class DevicePolicyManager { * @hide */ public List<String> getKeepUninstalledPackages(@NonNull ComponentName admin) { + throwIfParentInstance("getKeepUninstalledPackages"); if (mService != null) { try { return mService.getKeepUninstalledPackages(admin); @@ -4728,6 +4791,7 @@ public class DevicePolicyManager { */ public void setKeepUninstalledPackages(@NonNull ComponentName admin, @NonNull List<String> packageNames) { + throwIfParentInstance("setKeepUninstalledPackages"); if (mService != null) { try { mService.setKeepUninstalledPackages(admin, packageNames); @@ -4834,6 +4898,7 @@ public class DevicePolicyManager { public UserHandle createAndManageUser(@NonNull ComponentName admin, @NonNull String name, @NonNull ComponentName profileOwner, @Nullable PersistableBundle adminExtras, int flags) { + throwIfParentInstance("createAndManageUser"); try { return mService.createAndManageUser(admin, name, profileOwner, adminExtras, flags); } catch (RemoteException re) { @@ -4851,6 +4916,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device owner. */ public boolean removeUser(@NonNull ComponentName admin, UserHandle userHandle) { + throwIfParentInstance("removeUser"); try { return mService.removeUser(admin, userHandle); } catch (RemoteException re) { @@ -4868,6 +4934,7 @@ public class DevicePolicyManager { * @see Intent#ACTION_USER_FOREGROUND */ public boolean switchUser(@NonNull ComponentName admin, @Nullable UserHandle userHandle) { + throwIfParentInstance("switchUser"); try { return mService.switchUser(admin, userHandle); } catch (RemoteException re) { @@ -4893,6 +4960,7 @@ public class DevicePolicyManager { * @see {@link #setApplicationRestrictionsManagingPackage} */ public Bundle getApplicationRestrictions(@Nullable ComponentName admin, String packageName) { + throwIfParentInstance("getApplicationRestrictions"); if (mService != null) { try { return mService.getApplicationRestrictions(admin, packageName); @@ -4915,6 +4983,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device or profile owner. */ public void addUserRestriction(@NonNull ComponentName admin, String key) { + throwIfParentInstance("addUserRestriction"); if (mService != null) { try { mService.setUserRestriction(admin, key, true); @@ -4936,6 +5005,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device or profile owner. */ public void clearUserRestriction(@NonNull ComponentName admin, String key) { + throwIfParentInstance("clearUserRestriction"); if (mService != null) { try { mService.setUserRestriction(admin, key, false); @@ -4957,6 +5027,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device or profile owner. */ public Bundle getUserRestrictions(@NonNull ComponentName admin) { + throwIfParentInstance("getUserRestrictions"); Bundle ret = null; if (mService != null) { try { @@ -5001,6 +5072,7 @@ public class DevicePolicyManager { */ public boolean setApplicationHidden(@NonNull ComponentName admin, String packageName, boolean hidden) { + throwIfParentInstance("setApplicationHidden"); if (mService != null) { try { return mService.setApplicationHidden(admin, packageName, hidden); @@ -5020,6 +5092,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device or profile owner. */ public boolean isApplicationHidden(@NonNull ComponentName admin, String packageName) { + throwIfParentInstance("isApplicationHidden"); if (mService != null) { try { return mService.isApplicationHidden(admin, packageName); @@ -5039,6 +5112,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device or profile owner. */ public void enableSystemApp(@NonNull ComponentName admin, String packageName) { + throwIfParentInstance("enableSystemApp"); if (mService != null) { try { mService.enableSystemApp(admin, packageName); @@ -5059,6 +5133,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device or profile owner. */ public int enableSystemApp(@NonNull ComponentName admin, Intent intent) { + throwIfParentInstance("enableSystemApp"); if (mService != null) { try { return mService.enableSystemAppWithIntent(admin, intent); @@ -5091,6 +5166,7 @@ public class DevicePolicyManager { */ public void setAccountManagementDisabled(@NonNull ComponentName admin, String accountType, boolean disabled) { + throwIfParentInstance("setAccountManagementDisabled"); if (mService != null) { try { mService.setAccountManagementDisabled(admin, accountType, disabled); @@ -5111,6 +5187,7 @@ public class DevicePolicyManager { * @see #setAccountManagementDisabled */ public String[] getAccountTypesWithManagementDisabled() { + throwIfParentInstance("getAccountTypesWithManagementDisabled"); return getAccountTypesWithManagementDisabledAsUser(myUserId()); } @@ -5148,6 +5225,7 @@ public class DevicePolicyManager { */ public void setLockTaskPackages(@NonNull ComponentName admin, String[] packages) throws SecurityException { + throwIfParentInstance("setLockTaskPackages"); if (mService != null) { try { mService.setLockTaskPackages(admin, packages); @@ -5164,6 +5242,7 @@ public class DevicePolicyManager { * @hide */ public String[] getLockTaskPackages(@NonNull ComponentName admin) { + throwIfParentInstance("getLockTaskPackages"); if (mService != null) { try { return mService.getLockTaskPackages(admin); @@ -5180,6 +5259,7 @@ public class DevicePolicyManager { * @param pkg The package to check */ public boolean isLockTaskPermitted(String pkg) { + throwIfParentInstance("isLockTaskPermitted"); if (mService != null) { try { return mService.isLockTaskPermitted(pkg); @@ -5228,6 +5308,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device owner. */ public void setGlobalSetting(@NonNull ComponentName admin, String setting, String value) { + throwIfParentInstance("setGlobalSetting"); if (mService != null) { try { mService.setGlobalSetting(admin, setting, value); @@ -5260,6 +5341,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device or profile owner. */ public void setSecureSetting(@NonNull ComponentName admin, String setting, String value) { + throwIfParentInstance("setSecureSetting"); if (mService != null) { try { mService.setSecureSetting(admin, setting, value); @@ -5283,6 +5365,7 @@ public class DevicePolicyManager { */ public void setRestrictionsProvider(@NonNull ComponentName admin, @Nullable ComponentName provider) { + throwIfParentInstance("setRestrictionsProvider"); if (mService != null) { try { mService.setRestrictionsProvider(admin, provider); @@ -5300,6 +5383,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device or profile owner. */ public void setMasterVolumeMuted(@NonNull ComponentName admin, boolean on) { + throwIfParentInstance("setMasterVolumeMuted"); if (mService != null) { try { mService.setMasterVolumeMuted(admin, on); @@ -5317,6 +5401,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device or profile owner. */ public boolean isMasterVolumeMuted(@NonNull ComponentName admin) { + throwIfParentInstance("isMasterVolumeMuted"); if (mService != null) { try { return mService.isMasterVolumeMuted(admin); @@ -5337,6 +5422,7 @@ public class DevicePolicyManager { */ public void setUninstallBlocked(@NonNull ComponentName admin, String packageName, boolean uninstallBlocked) { + throwIfParentInstance("setUninstallBlocked"); if (mService != null) { try { mService.setUninstallBlocked(admin, packageName, uninstallBlocked); @@ -5362,6 +5448,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device or profile owner. */ public boolean isUninstallBlocked(@Nullable ComponentName admin, String packageName) { + throwIfParentInstance("isUninstallBlocked"); if (mService != null) { try { return mService.isUninstallBlocked(admin, packageName); @@ -5389,6 +5476,7 @@ public class DevicePolicyManager { * @see #getCrossProfileWidgetProviders(android.content.ComponentName) */ public boolean addCrossProfileWidgetProvider(@NonNull ComponentName admin, String packageName) { + throwIfParentInstance("addCrossProfileWidgetProvider"); if (mService != null) { try { return mService.addCrossProfileWidgetProvider(admin, packageName); @@ -5416,6 +5504,7 @@ public class DevicePolicyManager { */ public boolean removeCrossProfileWidgetProvider( @NonNull ComponentName admin, String packageName) { + throwIfParentInstance("removeCrossProfileWidgetProvider"); if (mService != null) { try { return mService.removeCrossProfileWidgetProvider(admin, packageName); @@ -5437,6 +5526,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a profile owner. */ public List<String> getCrossProfileWidgetProviders(@NonNull ComponentName admin) { + throwIfParentInstance("getCrossProfileWidgetProviders"); if (mService != null) { try { List<String> providers = mService.getCrossProfileWidgetProviders(admin); @@ -5458,6 +5548,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device or profile owner. */ public void setUserIcon(@NonNull ComponentName admin, Bitmap icon) { + throwIfParentInstance("setUserIcon"); try { mService.setUserIcon(admin, icon); } catch (RemoteException re) { @@ -5477,6 +5568,7 @@ public class DevicePolicyManager { * @see SystemUpdatePolicy */ public void setSystemUpdatePolicy(@NonNull ComponentName admin, SystemUpdatePolicy policy) { + throwIfParentInstance("setSystemUpdatePolicy"); if (mService != null) { try { mService.setSystemUpdatePolicy(admin, policy); @@ -5492,6 +5584,7 @@ public class DevicePolicyManager { * @return The current policy object, or {@code null} if no policy is set. */ public SystemUpdatePolicy getSystemUpdatePolicy() { + throwIfParentInstance("getSystemUpdatePolicy"); if (mService != null) { try { return mService.getSystemUpdatePolicy(); @@ -5517,6 +5610,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device owner. */ public boolean setKeyguardDisabled(@NonNull ComponentName admin, boolean disabled) { + throwIfParentInstance("setKeyguardDisabled"); try { return mService.setKeyguardDisabled(admin, disabled); } catch (RemoteException re) { @@ -5535,6 +5629,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device owner. */ public boolean setStatusBarDisabled(@NonNull ComponentName admin, boolean disabled) { + throwIfParentInstance("setStatusBarDisabled"); try { return mService.setStatusBarDisabled(admin, disabled); } catch (RemoteException re) { @@ -5553,6 +5648,7 @@ public class DevicePolicyManager { */ @SystemApi public void notifyPendingSystemUpdate(long updateReceivedTime) { + throwIfParentInstance("notifyPendingSystemUpdate"); if (mService != null) { try { mService.notifyPendingSystemUpdate(updateReceivedTime); @@ -5580,6 +5676,7 @@ public class DevicePolicyManager { * @see #setPermissionGrantState */ public void setPermissionPolicy(@NonNull ComponentName admin, int policy) { + throwIfParentInstance("setPermissionPolicy"); try { mService.setPermissionPolicy(admin, policy); } catch (RemoteException re) { @@ -5594,6 +5691,7 @@ public class DevicePolicyManager { * @return the current policy for future permission requests. */ public int getPermissionPolicy(ComponentName admin) { + throwIfParentInstance("getPermissionPolicy"); try { return mService.getPermissionPolicy(admin); } catch (RemoteException re) { @@ -5630,6 +5728,7 @@ public class DevicePolicyManager { */ public boolean setPermissionGrantState(@NonNull ComponentName admin, String packageName, String permission, int grantState) { + throwIfParentInstance("setPermissionGrantState"); try { return mService.setPermissionGrantState(admin, packageName, permission, grantState); } catch (RemoteException re) { @@ -5658,6 +5757,7 @@ public class DevicePolicyManager { */ public int getPermissionGrantState(@NonNull ComponentName admin, String packageName, String permission) { + throwIfParentInstance("getPermissionGrantState"); try { return mService.getPermissionGrantState(admin, packageName, permission); } catch (RemoteException re) { @@ -5673,6 +5773,7 @@ public class DevicePolicyManager { * @throws IllegalArgumentException if the supplied action is not valid. */ public boolean isProvisioningAllowed(String action) { + throwIfParentInstance("isProvisioningAllowed"); try { return mService.isProvisioningAllowed(action); } catch (RemoteException re) { @@ -5688,6 +5789,7 @@ public class DevicePolicyManager { * @return if this user is a managed profile of another user. */ public boolean isManagedProfile(@NonNull ComponentName admin) { + throwIfParentInstance("isManagedProfile"); try { return mService.isManagedProfile(admin); } catch (RemoteException re) { @@ -5721,6 +5823,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device owner. */ public String getWifiMacAddress(@NonNull ComponentName admin) { + throwIfParentInstance("getWifiMacAddress"); try { return mService.getWifiMacAddress(admin); } catch (RemoteException re) { @@ -5737,6 +5840,7 @@ public class DevicePolicyManager { * @see TelephonyManager#CALL_STATE_IDLE */ public void reboot(@NonNull ComponentName admin) { + throwIfParentInstance("reboot"); try { mService.reboot(admin); } catch (RemoteException re) { @@ -5763,6 +5867,7 @@ public class DevicePolicyManager { */ public void setShortSupportMessage(@NonNull ComponentName admin, @Nullable CharSequence message) { + throwIfParentInstance("setShortSupportMessage"); if (mService != null) { try { mService.setShortSupportMessage(admin, message); @@ -5781,6 +5886,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not an active administrator. */ public CharSequence getShortSupportMessage(@NonNull ComponentName admin) { + throwIfParentInstance("getShortSupportMessage"); if (mService != null) { try { return mService.getShortSupportMessage(admin); @@ -5807,6 +5913,7 @@ public class DevicePolicyManager { */ public void setLongSupportMessage(@NonNull ComponentName admin, @Nullable CharSequence message) { + throwIfParentInstance("setLongSupportMessage"); if (mService != null) { try { mService.setLongSupportMessage(admin, message); @@ -5825,6 +5932,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not an active administrator. */ public CharSequence getLongSupportMessage(@NonNull ComponentName admin) { + throwIfParentInstance("getLongSupportMessage"); if (mService != null) { try { return mService.getLongSupportMessage(admin); @@ -5922,6 +6030,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a profile owner. */ public DevicePolicyManager getParentProfileInstance(@NonNull ComponentName admin) { + throwIfParentInstance("getParentProfileInstance"); try { if (!mService.isManagedProfile(admin)) { throw new SecurityException("The current user does not have a parent profile."); @@ -5948,6 +6057,7 @@ public class DevicePolicyManager { * @see #retrieveSecurityLogs */ public void setSecurityLoggingEnabled(@NonNull ComponentName admin, boolean enabled) { + throwIfParentInstance("setSecurityLoggingEnabled"); try { mService.setSecurityLoggingEnabled(admin, enabled); } catch (RemoteException re) { @@ -5966,6 +6076,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device owner. */ public boolean isSecurityLoggingEnabled(@NonNull ComponentName admin) { + throwIfParentInstance("isSecurityLoggingEnabled"); try { return mService.isSecurityLoggingEnabled(admin); } catch (RemoteException re) { @@ -5989,6 +6100,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device owner. */ public List<SecurityEvent> retrieveSecurityLogs(@NonNull ComponentName admin) { + throwIfParentInstance("retrieveSecurityLogs"); try { ParceledListSlice<SecurityEvent> list = mService.retrieveSecurityLogs(admin); if (list != null) { @@ -6034,6 +6146,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device owner. */ public List<SecurityEvent> retrievePreRebootSecurityLogs(@NonNull ComponentName admin) { + throwIfParentInstance("retrievePreRebootSecurityLogs"); try { ParceledListSlice<SecurityEvent> list = mService.retrievePreRebootSecurityLogs(admin); return list.getList(); @@ -6055,6 +6168,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a profile owner. */ public void setOrganizationColor(@NonNull ComponentName admin, int color) { + throwIfParentInstance("setOrganizationColor"); try { // always enforce alpha channel to have 100% opacity color |= 0xFF000000; @@ -6094,6 +6208,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a profile owner. */ public @ColorInt int getOrganizationColor(@NonNull ComponentName admin) { + throwIfParentInstance("getOrganizationColor"); try { return mService.getOrganizationColor(admin); } catch (RemoteException re) { @@ -6129,6 +6244,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a profile owner. */ public void setOrganizationName(@NonNull ComponentName admin, @Nullable CharSequence title) { + throwIfParentInstance("setOrganizationName"); try { mService.setOrganizationName(admin, title); } catch (RemoteException re) { @@ -6145,6 +6261,7 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a profile owner. */ public CharSequence getOrganizationName(@NonNull ComponentName admin) { + throwIfParentInstance("getOrganizationName"); try { return mService.getOrganizationName(admin); } catch (RemoteException re) { @@ -6176,6 +6293,7 @@ public class DevicePolicyManager { @SystemApi @UserProvisioningState public int getUserProvisioningState() { + throwIfParentInstance("getUserProvisioningState"); if (mService != null) { try { return mService.getUserProvisioningState(); @@ -6222,6 +6340,7 @@ public class DevicePolicyManager { * @param ids A set of opaque affiliation ids. */ public void setAffiliationIds(@NonNull ComponentName admin, Set<String> ids) { + throwIfParentInstance("setAffiliationIds"); try { mService.setAffiliationIds(admin, new ArrayList<String>(ids)); } catch (RemoteException e) { @@ -6237,6 +6356,7 @@ public class DevicePolicyManager { * @return whether this user/profile is affiliated with the device. */ public boolean isAffiliatedUser() { + throwIfParentInstance("isAffiliatedUser"); try { return mService != null && mService.isAffiliatedUser(); } catch (RemoteException e) { @@ -6270,4 +6390,10 @@ public class DevicePolicyManager { throw re.rethrowFromSystemServer(); } } + + private void throwIfParentInstance(String functionName) { + if (mParentInstance) { + throw new SecurityException(functionName + " cannot be called on the parent instance"); + } + } } diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index aa1e372fe30d..4108f6dea139 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -1210,7 +1210,7 @@ public class PackageParser { // For those APKs we only care about extracting signer certificates, and don't care // about verifying integrity. boolean signatureSchemeRollbackProtectionsEnforced = - (parseFlags & PARSE_IS_SYSTEM) == 0; + (parseFlags & PARSE_IS_SYSTEM_DIR) == 0; jarFile = new StrictJarFile( apkPath, !verified, // whether to verify JAR signature @@ -1239,7 +1239,7 @@ public class PackageParser { toVerify.add(manifestEntry); // If we're parsing an untrusted package, verify all contents - if ((parseFlags & PARSE_IS_SYSTEM) == 0) { + if ((parseFlags & PARSE_IS_SYSTEM_DIR) == 0) { final Iterator<ZipEntry> i = jarFile.iterator(); while (i.hasNext()) { final ZipEntry entry = i.next(); @@ -1679,7 +1679,6 @@ public class PackageParser { private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res, XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException, IOException { - final boolean trustedOverlay = (flags & PARSE_TRUSTED_OVERLAY) != 0; mParseInstrumentationArgs = null; mParseActivityArgs = null; mParseServiceArgs = null; @@ -1769,8 +1768,6 @@ public class PackageParser { return null; } } else if (tagName.equals(TAG_OVERLAY)) { - pkg.mTrustedOverlay = trustedOverlay; - sa = res.obtainAttributes(parser, com.android.internal.R.styleable.AndroidManifestResourceOverlay); pkg.mOverlayTarget = sa.getString( @@ -2924,12 +2921,14 @@ public class PackageParser { ai.flags |= ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS; } - if (sa.getBoolean(R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage, - false) && (flags & PARSE_IS_SYSTEM) != 0) { + if (sa.getBoolean( + R.styleable.AndroidManifestApplication_defaultToDeviceProtectedStorage, + false)) { ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE; } - if (sa.getBoolean(R.styleable.AndroidManifestApplication_directBootAware, false) - && (flags & PARSE_IS_SYSTEM) != 0) { + if (sa.getBoolean( + R.styleable.AndroidManifestApplication_directBootAware, + false)) { ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE; } @@ -3554,7 +3553,7 @@ public class PackageParser { a.info.encryptionAware = a.info.directBootAware = sa.getBoolean( R.styleable.AndroidManifestActivity_directBootAware, - owner.applicationInfo.isDirectBootAware()); + false); } else { a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE; a.info.configChanges = 0; @@ -3572,7 +3571,7 @@ public class PackageParser { a.info.encryptionAware = a.info.directBootAware = sa.getBoolean( R.styleable.AndroidManifestActivity_directBootAware, - owner.applicationInfo.isDirectBootAware()); + false); } if (a.info.directBootAware) { @@ -3985,7 +3984,7 @@ public class PackageParser { p.info.encryptionAware = p.info.directBootAware = sa.getBoolean( R.styleable.AndroidManifestProvider_directBootAware, - owner.applicationInfo.isDirectBootAware()); + false); if (p.info.directBootAware) { owner.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE; @@ -4277,7 +4276,7 @@ public class PackageParser { s.info.encryptionAware = s.info.directBootAware = sa.getBoolean( R.styleable.AndroidManifestService_directBootAware, - owner.applicationInfo.isDirectBootAware()); + false); if (s.info.directBootAware) { owner.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE; diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index 4756b3728009..271ec79074e8 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -517,7 +517,8 @@ public class FingerprintManager { if (mService != null) try { mEnrollmentCallback = callback; - mService.enroll(mToken, token, userId, mServiceReceiver, flags); + mService.enroll(mToken, token, userId, mServiceReceiver, flags, + mContext.getOpPackageName()); } catch (RemoteException e) { Log.w(TAG, "Remote exception in enroll: ", e); if (callback != null) { diff --git a/core/java/android/hardware/fingerprint/IFingerprintDaemon.aidl b/core/java/android/hardware/fingerprint/IFingerprintDaemon.aidl index 9c13523e7b18..f40f8a3fdbf2 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintDaemon.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintDaemon.aidl @@ -35,4 +35,6 @@ interface IFingerprintDaemon { int closeHal(); void init(IFingerprintDaemonCallback callback); int postEnroll(); + int enumerate(); + int cancelEnumeration(); } diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl index 43d5577f3b71..d7915e3e9622 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl @@ -35,7 +35,7 @@ interface IFingerprintService { // Start fingerprint enrollment void enroll(IBinder token, in byte [] cryptoToken, int groupId, IFingerprintServiceReceiver receiver, - int flags); + int flags, String opPackageName); // Cancel enrollment in progress void cancelEnrollment(IBinder token); diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 5d008e3c8db1..9070ad9d03e8 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1131,7 +1131,8 @@ public class ConnectivityManager { * implementation+feature combination, except that the value {@code -1} * always indicates failure. * - * @deprecated Deprecated in favor of the cleaner {@link #unregisterNetworkCallback} API. + * @deprecated Deprecated in favor of the cleaner + * {@link #unregisterNetworkCallback(NetworkCallback)} API. * In {@link VERSION_CODES#M}, and above, this method is unsupported and will * throw {@code UnsupportedOperationException} if called. */ @@ -2811,7 +2812,7 @@ public class ConnectivityManager { * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}. * * This {@link NetworkRequest} will live until released via - * {@link #unregisterNetworkCallback} or the calling application exits. + * {@link #unregisterNetworkCallback(NetworkCallback)} or the calling application exits. * Status of the request can be followed by listening to the various * callbacks described in {@link NetworkCallback}. The {@link Network} * can be used to direct traffic to the network. @@ -2848,7 +2849,7 @@ public class ConnectivityManager { * This function behaves identically to the non-timedout version, but if a suitable * network is not found within the given time (in milliseconds) the * {@link NetworkCallback#unavailable} callback is called. The request must - * still be released normally by calling {@link unregisterNetworkCallback}. + * still be released normally by calling {@link unregisterNetworkCallback(NetworkCallback)}. * * <p>This method requires the caller to hold either the * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission @@ -2956,7 +2957,8 @@ public class ConnectivityManager { /** * Removes a request made via {@link #requestNetwork(NetworkRequest, android.app.PendingIntent)} * <p> - * This method has the same behavior as {@link #unregisterNetworkCallback} with respect to + * This method has the same behavior as + * {@link #unregisterNetworkCallback(android.app.PendingIntent)} with respect to * releasing network resources and disconnecting. * * @param operation A PendingIntent equal (as defined by {@link Intent#filterEquals}) to the @@ -2982,7 +2984,7 @@ public class ConnectivityManager { /** * Registers to receive notifications about all networks which satisfy the given * {@link NetworkRequest}. The callbacks will continue to be called until - * either the application exits or {@link #unregisterNetworkCallback} is called + * either the application exits or link #unregisterNetworkCallback(NetworkCallback)} is called. * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * @@ -3035,9 +3037,9 @@ public class ConnectivityManager { } /** - * Registers to receive notifications about whichever network currently satisfies the - * system default {@link NetworkRequest}. The callbacks will continue to be called until - * either the application exits or {@link #unregisterNetworkCallback} is called + * Registers to receive notifications about changes in the system default network. The callbacks + * will continue to be called until either the application exits or + * {@link #unregisterNetworkCallback(NetworkCallback)} is called. * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * @@ -3060,8 +3062,9 @@ public class ConnectivityManager { * is accepted by ConnectivityService. Once accepted, ConnectivityService will poll underlying * network connection for updated bandwidth information. The caller will be notified via * {@link ConnectivityManager.NetworkCallback} if there is an update. Notice that this - * method assumes that the caller has previously called {@link #registerNetworkCallback} to - * listen for network changes. + * method assumes that the caller has previously called + * {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)} to listen for network + * changes. * * @param network {@link Network} specifying which network you're interested. * @return {@code true} on success, {@code false} if the {@link Network} is no longer valid. @@ -3076,8 +3079,9 @@ public class ConnectivityManager { /** * Unregisters callbacks about and possibly releases networks originating from - * {@link #requestNetwork(NetworkRequest, NetworkCallback)} and {@link #registerNetworkCallback} - * calls. If the given {@code NetworkCallback} had previously been used with + * {@link #requestNetwork(NetworkRequest, NetworkCallback)} and + * {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)} calls. + * If the given {@code NetworkCallback} had previously been used with * {@code #requestNetwork}, any networks that had been connected to only to satisfy that request * will be disconnected. * diff --git a/core/java/android/net/ConnectivityMetricsEvent.java b/core/java/android/net/ConnectivityMetricsEvent.java index b5d67d38455d..5153ba903ecf 100644 --- a/core/java/android/net/ConnectivityMetricsEvent.java +++ b/core/java/android/net/ConnectivityMetricsEvent.java @@ -16,10 +16,12 @@ package android.net; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; /** {@hide} */ +@SystemApi public final class ConnectivityMetricsEvent implements Parcelable { /** The time when this event was collected, as returned by System.currentTimeMillis(). */ @@ -80,12 +82,13 @@ public final class ConnectivityMetricsEvent implements Parcelable { } /** {@hide} */ - public static class Reference implements Parcelable { + @SystemApi + public final static class Reference implements Parcelable { - public long value; + private long mValue; public Reference(long ref) { - this.value = ref; + this.mValue = ref; } /** Implement the Parcelable interface */ @@ -109,11 +112,19 @@ public final class ConnectivityMetricsEvent implements Parcelable { /** Implement the Parcelable interface */ @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeLong(value); + dest.writeLong(mValue); } public void readFromParcel(Parcel in) { - value = in.readLong(); + mValue = in.readLong(); + } + + public long getValue() { + return mValue; + } + + public void setValue(long val) { + mValue = val; } } } diff --git a/core/java/android/net/ConnectivityMetricsLogger.java b/core/java/android/net/ConnectivityMetricsLogger.java index eafb8acb8aeb..b49cc2bffa16 100644 --- a/core/java/android/net/ConnectivityMetricsLogger.java +++ b/core/java/android/net/ConnectivityMetricsLogger.java @@ -15,6 +15,7 @@ */ package android.net; +import android.annotation.SystemApi; import android.os.Bundle; import android.os.Parcelable; import android.os.RemoteException; @@ -22,6 +23,7 @@ import android.os.ServiceManager; import android.util.Log; /** {@hide} */ +@SystemApi public class ConnectivityMetricsLogger { private static String TAG = "ConnectivityMetricsLogger"; private static final boolean DBG = true; diff --git a/core/java/android/net/metrics/DnsEvent.java b/core/java/android/net/metrics/DnsEvent.java new file mode 100644 index 000000000000..200b81645409 --- /dev/null +++ b/core/java/android/net/metrics/DnsEvent.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.metrics; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * {@hide} + */ +public class DnsEvent extends IpConnectivityEvent implements Parcelable { + public final int netId; + + // The event type is currently only 1 or 2, so we store it as a byte. + public final byte[] eventTypes; + // Current getaddrinfo codes go from 1 to EAI_MAX = 15. gethostbyname returns errno, but there + // are fewer than 255 errno values. So we store the result code in a byte as well. + public final byte[] returnCodes; + // The latency is an integer because a) short arrays aren't parcelable and b) a short can only + // store a maximum latency of 32757 or 65535 ms, which is too short for pathologically slow + // queries. + public final int[] latenciesMs; + + private DnsEvent(int netId, byte[] eventTypes, byte[] returnCodes, int[] latenciesMs) { + this.netId = netId; + this.eventTypes = eventTypes; + this.returnCodes = returnCodes; + this.latenciesMs = latenciesMs; + } + + private DnsEvent(Parcel in) { + netId = in.readInt(); + eventTypes = in.createByteArray(); + returnCodes = in.createByteArray(); + latenciesMs = in.createIntArray(); + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(netId); + out.writeByteArray(eventTypes); + out.writeByteArray(returnCodes); + out.writeIntArray(latenciesMs); + } + + public static final Parcelable.Creator<DnsEvent> CREATOR = new Parcelable.Creator<DnsEvent>() { + @Override + public DnsEvent createFromParcel(Parcel in) { + return new DnsEvent(in); + } + + @Override + public DnsEvent[] newArray(int size) { + return new DnsEvent[size]; + } + }; + + public static void logEvent( + int netId, byte[] eventTypes, byte[] returnCodes, int[] latenciesMs) { + IpConnectivityEvent.logEvent(IPCE_DNS_LOOKUPS, + new DnsEvent(netId, eventTypes, returnCodes, latenciesMs)); + } +} diff --git a/core/java/android/net/metrics/IpConnectivityEvent.java b/core/java/android/net/metrics/IpConnectivityEvent.java index 59c1cfe25be0..f0a3c902a355 100644 --- a/core/java/android/net/metrics/IpConnectivityEvent.java +++ b/core/java/android/net/metrics/IpConnectivityEvent.java @@ -24,31 +24,39 @@ import android.os.Parcelable; * {@hide} */ public class IpConnectivityEvent implements Parcelable { - // IPRM = IpReachabilityMonitor - // DHCP = DhcpClient + public static final String TAG = "IpConnectivityEvent"; + + // IPRM = IpReachabilityMonitor + // DHCP = DhcpClient // NETMON = NetworkMonitorEvent // CONSRV = ConnectivityServiceEvent - // IPMGR = IpManager - public static final String TAG = "IpConnectivityEvent"; - public static final int IPCE_IPRM_BASE = 0*1024; - public static final int IPCE_DHCP_BASE = 1*1024; - public static final int IPCE_NETMON_BASE = 2*1024; - public static final int IPCE_CONSRV_BASE = 3*1024; - public static final int IPCE_IPMGR_BASE = 4*1024; + // IPMGR = IpManager + public static final int IPCE_IPRM_BASE = 0 * 1024; + public static final int IPCE_DHCP_BASE = 1 * 1024; + public static final int IPCE_NETMON_BASE = 2 * 1024; + public static final int IPCE_CONSRV_BASE = 3 * 1024; + public static final int IPCE_IPMGR_BASE = 4 * 1024; + public static final int IPCE_DNS_BASE = 5 * 1024; + + public static final int IPCE_IPRM_PROBE_RESULT = IPCE_IPRM_BASE + 0; + public static final int IPCE_IPRM_MESSAGE_RECEIVED = IPCE_IPRM_BASE + 1; + public static final int IPCE_IPRM_REACHABILITY_LOST = IPCE_IPRM_BASE + 2; + + public static final int IPCE_DHCP_RECV_ERROR = IPCE_DHCP_BASE + 0; + public static final int IPCE_DHCP_PARSE_ERROR = IPCE_DHCP_BASE + 1; + public static final int IPCE_DHCP_TIMEOUT = IPCE_DHCP_BASE + 2; + public static final int IPCE_DHCP_STATE_CHANGE = IPCE_DHCP_BASE + 3; + + public static final int IPCE_NETMON_STATE_CHANGE = IPCE_NETMON_BASE + 0; + public static final int IPCE_NETMON_CHECK_RESULT = IPCE_NETMON_BASE + 1; - public static final int IPCE_IPRM_PROBE_RESULT = IPCE_IPRM_BASE + 0; - public static final int IPCE_IPRM_MESSAGE_RECEIVED = IPCE_IPRM_BASE + 1; - public static final int IPCE_IPRM_REACHABILITY_LOST = IPCE_IPRM_BASE + 2; - public static final int IPCE_DHCP_RECV_ERROR = IPCE_DHCP_BASE + 0; - public static final int IPCE_DHCP_PARSE_ERROR = IPCE_DHCP_BASE + 1; - public static final int IPCE_DHCP_TIMEOUT = IPCE_DHCP_BASE + 2; - public static final int IPCE_DHCP_STATE_CHANGE = IPCE_DHCP_BASE + 3; - public static final int IPCE_NETMON_STATE_CHANGE = IPCE_NETMON_BASE + 0; - public static final int IPCE_NETMON_CHECK_RESULT = IPCE_NETMON_BASE + 1; public static final int IPCE_CONSRV_DEFAULT_NET_CHANGE = IPCE_CONSRV_BASE + 0; - public static final int IPCE_IPMGR_PROVISIONING_OK = IPCE_IPMGR_BASE + 0; - public static final int IPCE_IPMGR_PROVISIONING_FAIL = IPCE_IPMGR_BASE + 1; - public static final int IPCE_IPMGR_COMPLETE_LIFECYCLE = IPCE_IPMGR_BASE + 2; + + public static final int IPCE_IPMGR_PROVISIONING_OK = IPCE_IPMGR_BASE + 0; + public static final int IPCE_IPMGR_PROVISIONING_FAIL = IPCE_IPMGR_BASE + 1; + public static final int IPCE_IPMGR_COMPLETE_LIFECYCLE = IPCE_IPMGR_BASE + 2; + + public static final int IPCE_DNS_LOOKUPS = IPCE_DNS_BASE + 0; private static ConnectivityMetricsLogger mMetricsLogger = new ConnectivityMetricsLogger(); diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index 67d395954e1e..55b0d2a15317 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -20,6 +20,7 @@ package android.os; import android.os.Bundle; import android.os.PersistableBundle; import android.content.pm.UserInfo; +import android.content.IntentSender; import android.content.RestrictionEntry; import android.graphics.Bitmap; import android.os.ParcelFileDescriptor; @@ -70,6 +71,7 @@ interface IUserManager { boolean markGuestForDeletion(int userHandle); void setQuietModeEnabled(int userHandle, boolean enableQuietMode); boolean isQuietModeEnabled(int userHandle); + boolean trySetQuietModeDisabled(int userHandle, in IntentSender target); void setSeedAccountData(int userHandle, in String accountName, in String accountType, in PersistableBundle accountOptions, boolean persist); String getSeedAccountName(); diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index d5b3b3518701..086a9776aa8f 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -29,6 +29,7 @@ import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.IntentSender; import android.content.pm.UserInfo; import android.content.res.Resources; import android.graphics.Bitmap; @@ -1691,6 +1692,23 @@ public class UserManager { } /** + * Tries disabling quiet mode for a given user. If the user is still locked, we unlock the user + * first by showing the confirm credentials screen and disable quiet mode upon successful + * unlocking. If the user is already unlocked, we call through to {@link #setQuietModeEnabled} + * directly. + * + * @return true if the quiet mode was disabled immediately + * @hide + */ + public boolean trySetQuietModeDisabled(@UserIdInt int userHandle, IntentSender target) { + try { + return mService.trySetQuietModeDisabled(userHandle, target); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** * If the target user is a managed profile of the calling user or the caller * is itself a managed profile, then this returns a badged copy of the given * icon to be able to distinguish it from the original icon. For badging an diff --git a/core/java/android/view/DisplayListCanvas.java b/core/java/android/view/DisplayListCanvas.java index 080ed9ae1841..2481e049933b 100644 --- a/core/java/android/view/DisplayListCanvas.java +++ b/core/java/android/view/DisplayListCanvas.java @@ -163,17 +163,33 @@ public class DisplayListCanvas extends Canvas { /////////////////////////////////////////////////////////////////////////// /** - * Calls the function specified with the drawGLFunction function pointer. This is - * functionality used by webkit for calling into their renderer from our display lists. - * This function may return true if an invalidation is needed after the call. + * Records the functor specified with the drawGLFunction function pointer. This is + * functionality used by webview for calling into their renderer from our display lists. * * @param drawGLFunction A native function pointer */ public void callDrawGLFunction2(long drawGLFunction) { - nCallDrawGLFunction(mNativeCanvasWrapper, drawGLFunction); + nCallDrawGLFunction(mNativeCanvasWrapper, drawGLFunction, null); } - private static native void nCallDrawGLFunction(long renderer, long drawGLFunction); + /** + * Records the functor specified with the drawGLFunction function pointer. This is + * functionality used by webview for calling into their renderer from our display lists. + * + * @param drawGLFunction A native function pointer + * @param releasedCallback Called when the display list is destroyed, and thus + * the functor is no longer referenced by this canvas's display list. + * + * NOTE: The callback does *not* necessarily mean that there are no longer + * any references to the functor, just that the reference from this specific + * canvas's display list has been released. + */ + public void drawGLFunctor2(long drawGLFunctor, Runnable releasedCallback) { + nCallDrawGLFunction(mNativeCanvasWrapper, drawGLFunctor, releasedCallback); + } + + private static native void nCallDrawGLFunction(long renderer, + long drawGLFunction, Runnable releasedCallback); /////////////////////////////////////////////////////////////////////////// // Display list diff --git a/core/java/android/view/IDockedStackListener.aidl b/core/java/android/view/IDockedStackListener.aidl index 88ac27118406..36a81db2880a 100644 --- a/core/java/android/view/IDockedStackListener.aidl +++ b/core/java/android/view/IDockedStackListener.aidl @@ -44,6 +44,15 @@ oneway interface IDockedStackListener { void onDockedStackMinimizedChanged(boolean minimized, long animDuration); /** + * Called when window manager decides to adjust the divider for IME. Like the minimized state, + * the divider should make itself not interactable and shrink a bit, but in a different way.s + * + * @param minimized Whether the stacks are currently adjusted for the IME + * @param animDuration The duration of the animation for changing the adjusted state. + */ + void onAdjustedForImeChanged(boolean adjustedForIme, long animDuration); + + /** * Called when window manager repositioned the docked stack after a screen rotation change. */ void onDockSideChanged(int newDockSide); diff --git a/core/java/com/android/internal/app/UnlaunchableAppActivity.java b/core/java/com/android/internal/app/UnlaunchableAppActivity.java index 27588e98dcaf..d24cefeecf07 100644 --- a/core/java/com/android/internal/app/UnlaunchableAppActivity.java +++ b/core/java/com/android/internal/app/UnlaunchableAppActivity.java @@ -107,9 +107,8 @@ public class UnlaunchableAppActivity extends Activity @Override public void onClick(DialogInterface dialog, int which) { if (mReason == UNLAUNCHABLE_REASON_QUIET_MODE && which == DialogInterface.BUTTON_POSITIVE) { - UserManager.get(this).setQuietModeEnabled(mUserId, false); - - if (mTarget != null) { + if (UserManager.get(this).trySetQuietModeDisabled(mUserId, mTarget) + && mTarget != null) { try { startIntentSenderForResult(mTarget, -1, null, 0, 0, 0); } catch (IntentSender.SendIntentException e) { diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index 9e5c2383c008..36e21b977f6d 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -63,7 +63,7 @@ oneway interface IStatusBar void toggleSplitScreen(); void preloadRecentApps(); void cancelPreloadRecentApps(); - void showScreenPinningRequest(); + void showScreenPinningRequest(int taskId); void toggleKeyboardShortcutsMenu(int deviceId); diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp index f46f45cc5e5d..898cf77cb32d 100644 --- a/core/jni/android/graphics/Paint.cpp +++ b/core/jni/android/graphics/Paint.cpp @@ -815,10 +815,15 @@ namespace PaintGlue { } if (prevCp != kStartOfString && - ((0xFE00 <= cp && cp <= 0xFE0F) || (0xE0100 <= cp && cp <= 0xE01EF)) && - !MinikinUtils::hasVariationSelector(typeface, prevCp, cp)) { - // No font has a glyph for the code point and variation selector pair. - return false; + ((0xFE00 <= cp && cp <= 0xFE0F) || (0xE0100 <= cp && cp <= 0xE01EF))) { + bool hasVS = MinikinUtils::hasVariationSelector(typeface, prevCp, cp); + if (!hasVS) { + // No font has a glyph for the code point and variation selector pair. + return false; + } else if (nChars == 1 && i + 1 == str.size()) { + // The string is just a codepoint and a VS, we have an authoritative answer + return true; + } } nChars++; prevCp = cp; diff --git a/core/jni/android_view_DisplayListCanvas.cpp b/core/jni/android_view_DisplayListCanvas.cpp index 6aac0e4975e8..cadfd3d89a2a 100644 --- a/core/jni/android_view_DisplayListCanvas.cpp +++ b/core/jni/android_view_DisplayListCanvas.cpp @@ -22,12 +22,12 @@ #include <android_runtime/AndroidRuntime.h> +#include <utils/Looper.h> #include <cutils/properties.h> #include <SkBitmap.h> #include <SkRegion.h> - #include <Rect.h> #include <RenderNode.h> #include <CanvasProperty.h> @@ -41,6 +41,52 @@ namespace android { using namespace uirenderer; +jmethodID gRunnableMethodId; + +static JNIEnv* jnienv(JavaVM* vm) { + JNIEnv* env; + if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { + LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", vm); + } + return env; +} + +class InvokeRunnableMessage : public MessageHandler { +public: + InvokeRunnableMessage(JNIEnv* env, jobject runnable) { + mRunnable = env->NewGlobalRef(runnable); + env->GetJavaVM(&mVm); + } + + virtual ~InvokeRunnableMessage() { + jnienv(mVm)->DeleteGlobalRef(mRunnable); + } + + virtual void handleMessage(const Message&) { + jnienv(mVm)->CallVoidMethod(mRunnable, gRunnableMethodId); + } + +private: + JavaVM* mVm; + jobject mRunnable; +}; + +class GlFunctorReleasedCallbackBridge : public GlFunctorLifecycleListener { +public: + GlFunctorReleasedCallbackBridge(JNIEnv* env, jobject javaCallback) { + mLooper = Looper::getForThread(); + mMessage = new InvokeRunnableMessage(env, javaCallback); + } + + virtual void onGlFunctorReleased(Functor* functor) override { + mLooper->sendMessage(mMessage, 0); + } + +private: + sp<Looper> mLooper; + sp<InvokeRunnableMessage> mMessage; +}; + // ---------------------------------------------------------------------------- // Setup // ---------------------------------------------------------------------------- @@ -56,10 +102,12 @@ static void android_view_DisplayListCanvas_insertReorderBarrier(JNIEnv* env, job // ---------------------------------------------------------------------------- static void android_view_DisplayListCanvas_callDrawGLFunction(JNIEnv* env, jobject clazz, - jlong canvasPtr, jlong functorPtr) { + jlong canvasPtr, jlong functorPtr, jobject releasedCallback) { Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr); Functor* functor = reinterpret_cast<Functor*>(functorPtr); - canvas->callDrawGLFunction(functor); + sp<GlFunctorReleasedCallbackBridge> bridge(new GlFunctorReleasedCallbackBridge( + env, releasedCallback)); + canvas->callDrawGLFunction(functor, bridge.get()); } // ---------------------------------------------------------------------------- @@ -184,7 +232,8 @@ static JNINativeMethod gMethods[] = { { "nIsAvailable", "!()Z", (void*) android_view_DisplayListCanvas_isAvailable }, { "nInsertReorderBarrier","!(JZ)V", (void*) android_view_DisplayListCanvas_insertReorderBarrier }, - { "nCallDrawGLFunction", "!(JJ)V", (void*) android_view_DisplayListCanvas_callDrawGLFunction }, + { "nCallDrawGLFunction", "!(JJLjava/lang/Runnable;)V", + (void*) android_view_DisplayListCanvas_callDrawGLFunction }, { "nDrawRoundRect", "!(JJJJJJJJ)V", (void*) android_view_DisplayListCanvas_drawRoundRectProps }, { "nDrawCircle", "!(JJJJJ)V", (void*) android_view_DisplayListCanvas_drawCircleProps }, @@ -207,6 +256,9 @@ static JNINativeMethod gActivityThreadMethods[] = { }; int register_android_view_DisplayListCanvas(JNIEnv* env) { + jclass runnableClass = FindClassOrDie(env, "java/lang/Runnable"); + gRunnableMethodId = GetMethodIDOrDie(env, runnableClass, "run", "()V"); + return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods)); } diff --git a/core/res/res/anim/input_method_exit.xml b/core/res/res/anim/input_method_exit.xml index 117774aff802..575404d2775f 100644 --- a/core/res/res/anim/input_method_exit.xml +++ b/core/res/res/anim/input_method_exit.xml @@ -17,10 +17,10 @@ --> <set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false"> - <translate android:fromYDelta="0" android:toYDelta="10%" - android:interpolator="@interpolator/accelerate_quint" - android:duration="@android:integer/config_shortAnimTime"/> + <translate android:fromYDelta="0" android:toYDelta="8%" + android:interpolator="@interpolator/fast_out_linear_in" + android:duration="150"/> <alpha android:fromAlpha="1.0" android:toAlpha="0.0" - android:interpolator="@interpolator/accelerate_cubic" - android:duration="@android:integer/config_shortAnimTime"/> + android:interpolator="@interpolator/fast_out_linear_in" + android:duration="150"/> </set> diff --git a/core/res/res/layout/floating_popup_overflow_button.xml b/core/res/res/layout/floating_popup_overflow_button.xml index 7053f3ec07fe..12e200088286 100644 --- a/core/res/res/layout/floating_popup_overflow_button.xml +++ b/core/res/res/layout/floating_popup_overflow_button.xml @@ -24,5 +24,5 @@ android:paddingEnd="@dimen/floating_toolbar_menu_button_side_padding" android:paddingBottom="@dimen/floating_toolbar_menu_image_button_vertical_padding" android:scaleType="centerInside" - android:background="?attr/selectableItemBackgroundBorderless" + android:background="?attr/actionBarItemBackground" android:tint="?attr/floatingToolbarForegroundColor" /> diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 717a1e6eacc4..62594667086a 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -7,7 +7,7 @@ HWUI_NEW_OPS := true # Enables fine-grained GLES error checking # If set to true, every GLES call is wrapped & error checked # Has moderate overhead -HWUI_ENABLE_OPENGL_VALIDATION := true +HWUI_ENABLE_OPENGL_VALIDATION := false hwui_src_files := \ font/CacheTexture.cpp \ diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp index 181b3433381c..b572bdaccb86 100644 --- a/libs/hwui/DisplayList.cpp +++ b/libs/hwui/DisplayList.cpp @@ -73,6 +73,12 @@ void DisplayList::cleanupResources() { delete path; } + for (auto& iter : functors) { + if (iter.listener) { + iter.listener->onGlFunctorReleased(iter.functor); + } + } + patchResources.clear(); pathResources.clear(); paints.clear(); diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h index aba5d4bd218d..5b3227b7db97 100644 --- a/libs/hwui/DisplayList.h +++ b/libs/hwui/DisplayList.h @@ -35,6 +35,7 @@ #include "Debug.h" #include "CanvasProperty.h" #include "DeferredDisplayList.h" +#include "GlFunctorLifecycleListener.h" #include "Matrix.h" #include "RenderProperties.h" @@ -119,6 +120,11 @@ struct PushStagingFunctor { virtual void operator ()() {} }; +struct FunctorContainer { + Functor* functor; + GlFunctorLifecycleListener* listener; +}; + /** * Data structure that holds the list of commands used in display list stream */ @@ -154,7 +160,7 @@ public: const LsaVector<NodeOpType*>& getChildren() const { return children; } const LsaVector<const SkBitmap*>& getBitmapResources() const { return bitmapResources; } - const LsaVector<Functor*>& getFunctors() const { return functors; } + const LsaVector<FunctorContainer>& getFunctors() const { return functors; } const LsaVector<PushStagingFunctor*>& getPushStagingFunctors() { return pushStagingFunctors; } size_t addChild(NodeOpType* childOp); @@ -195,7 +201,7 @@ private: LsaVector< sp<VirtualLightRefBase> > referenceHolders; // List of functors - LsaVector<Functor*> functors; + LsaVector<FunctorContainer> functors; // List of functors that need to be notified of pushStaging. Note that this list gets nothing // but a callback during sync DisplayList, unlike the list of functors defined above, which diff --git a/libs/hwui/DisplayListCanvas.cpp b/libs/hwui/DisplayListCanvas.cpp index c6e92abbe0c3..ca968cef91b2 100644 --- a/libs/hwui/DisplayListCanvas.cpp +++ b/libs/hwui/DisplayListCanvas.cpp @@ -81,9 +81,11 @@ DisplayList* DisplayListCanvas::finishRecording() { return displayList; } -void DisplayListCanvas::callDrawGLFunction(Functor *functor) { +void DisplayListCanvas::callDrawGLFunction(Functor* functor, + GlFunctorLifecycleListener* listener) { addDrawOp(new (alloc()) DrawFunctorOp(functor)); - mDisplayList->functors.push_back(functor); + mDisplayList->functors.push_back({functor, listener}); + mDisplayList->ref(listener); } SkCanvas* DisplayListCanvas::asSkCanvas() { diff --git a/libs/hwui/DisplayListCanvas.h b/libs/hwui/DisplayListCanvas.h index d6a5794734d6..664f79e283b6 100644 --- a/libs/hwui/DisplayListCanvas.h +++ b/libs/hwui/DisplayListCanvas.h @@ -93,7 +93,8 @@ public: // ---------------------------------------------------------------------------- virtual void drawLayer(DeferredLayerUpdater* layerHandle) override; virtual void drawRenderNode(RenderNode* renderNode) override; - virtual void callDrawGLFunction(Functor* functor) override; + virtual void callDrawGLFunction(Functor* functor, + GlFunctorLifecycleListener* listener) override; // ---------------------------------------------------------------------------- // CanvasStateClient interface diff --git a/libs/hwui/GlFunctorLifecycleListener.h b/libs/hwui/GlFunctorLifecycleListener.h new file mode 100644 index 000000000000..357090eb31ca --- /dev/null +++ b/libs/hwui/GlFunctorLifecycleListener.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include <utils/Functor.h> +#include <utils/RefBase.h> + +namespace android { +namespace uirenderer { + +class GlFunctorLifecycleListener : public VirtualLightRefBase { +public: + virtual ~GlFunctorLifecycleListener() {} + virtual void onGlFunctorReleased(Functor* functor) = 0; +}; + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp index ab733f138b25..b49f9b529989 100644 --- a/libs/hwui/RecordingCanvas.cpp +++ b/libs/hwui/RecordingCanvas.cpp @@ -594,8 +594,10 @@ void RecordingCanvas::drawLayer(DeferredLayerUpdater* layerHandle) { layerHandle->backingLayer())); } -void RecordingCanvas::callDrawGLFunction(Functor* functor) { - mDisplayList->functors.push_back(functor); +void RecordingCanvas::callDrawGLFunction(Functor* functor, + GlFunctorLifecycleListener* listener) { + mDisplayList->functors.push_back({functor, listener}); + mDisplayList->ref(listener); addOp(alloc().create_trivial<FunctorOp>( *(mState.currentSnapshot()->transform), getRecordedClip(), diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h index 219296c97bb6..372be241042a 100644 --- a/libs/hwui/RecordingCanvas.h +++ b/libs/hwui/RecordingCanvas.h @@ -59,7 +59,8 @@ public: virtual void drawLayer(DeferredLayerUpdater* layerHandle) override; virtual void drawRenderNode(RenderNode* renderNode) override; - virtual void callDrawGLFunction(Functor* functor) override; + virtual void callDrawGLFunction(Functor* functor, + GlFunctorLifecycleListener* listener) override; // ---------------------------------------------------------------------------- // CanvasStateClient interface diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index ea06fcd092ce..6e848fddf48f 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -474,8 +474,8 @@ void RenderNode::syncDisplayList(TreeObserver* observer) { mDisplayList = mStagingDisplayList; mStagingDisplayList = nullptr; if (mDisplayList) { - for (size_t i = 0; i < mDisplayList->getFunctors().size(); i++) { - (*mDisplayList->getFunctors()[i])(DrawGlInfo::kModeSync, nullptr); + for (auto& iter : mDisplayList->getFunctors()) { + (*iter.functor)(DrawGlInfo::kModeSync, nullptr); } for (size_t i = 0; i < mDisplayList->getPushStagingFunctors().size(); i++) { (*mDisplayList->getPushStagingFunctors()[i])(); diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp index 1b459c142561..ce67554645d1 100644 --- a/libs/hwui/SkiaCanvas.cpp +++ b/libs/hwui/SkiaCanvas.cpp @@ -160,7 +160,8 @@ public: virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) override; virtual void drawRenderNode(uirenderer::RenderNode* renderNode) override; - virtual void callDrawGLFunction(Functor* functor) override; + virtual void callDrawGLFunction(Functor* functor, + uirenderer::GlFunctorLifecycleListener* listener) override; protected: virtual void drawGlyphs(const uint16_t* text, const float* positions, int count, @@ -846,6 +847,7 @@ void SkiaCanvas::drawLayer(uirenderer::DeferredLayerUpdater* layer) { } void SkiaCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) { } -void SkiaCanvas::callDrawGLFunction(Functor* functor) { } +void SkiaCanvas::callDrawGLFunction(Functor* functor, + uirenderer::GlFunctorLifecycleListener* listener) { } } // namespace android diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h index 691cfa01a498..1c6f48e7276b 100644 --- a/libs/hwui/VectorDrawable.h +++ b/libs/hwui/VectorDrawable.h @@ -219,22 +219,24 @@ public: int fillType = 0; /* non-zero or kWinding_FillType in Skia */ }; FullPathProperties(Node* mNode) : Properties(mNode), mTrimDirty(false) {} + ~FullPathProperties() { + SkSafeUnref(fillGradient); + SkSafeUnref(strokeGradient); + } void syncProperties(const FullPathProperties& prop) { mPrimitiveFields = prop.mPrimitiveFields; mTrimDirty = true; - fillGradient.reset(prop.fillGradient); - strokeGradient.reset(prop.strokeGradient); + UPDATE_SKPROP(fillGradient, prop.fillGradient); + UPDATE_SKPROP(strokeGradient, prop.strokeGradient); onPropertyChanged(); } void setFillGradient(SkShader* gradient) { - if(fillGradient != gradient){ - fillGradient.reset(gradient); + if(UPDATE_SKPROP(fillGradient, gradient)) { onPropertyChanged(); } } void setStrokeGradient(SkShader* gradient) { - if(strokeGradient != gradient){ - strokeGradient.reset(gradient); + if(UPDATE_SKPROP(strokeGradient, gradient)) { onPropertyChanged(); } } @@ -346,8 +348,8 @@ public: count, }; PrimitiveFields mPrimitiveFields; - SkAutoTUnref<SkShader> fillGradient; - SkAutoTUnref<SkShader> strokeGradient; + SkShader* fillGradient = nullptr; + SkShader* strokeGradient = nullptr; }; // Called from UI thread diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h index 5dbda43cec47..55af33e80256 100644 --- a/libs/hwui/hwui/Canvas.h +++ b/libs/hwui/hwui/Canvas.h @@ -20,6 +20,7 @@ #include <cutils/compiler.h> #include <utils/Functor.h> +#include "GlFunctorLifecycleListener.h" #include "utils/NinePatch.h" #include <SkBitmap.h> @@ -124,7 +125,8 @@ public: virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) = 0; virtual void drawRenderNode(uirenderer::RenderNode* renderNode) = 0; - virtual void callDrawGLFunction(Functor* functor) = 0; + virtual void callDrawGLFunction(Functor* functor, + uirenderer::GlFunctorLifecycleListener* listener) = 0; // ---------------------------------------------------------------------------- // Canvas state operations diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp index 209a10483a8e..ebc1c8002304 100644 --- a/libs/hwui/tests/unit/FrameBuilderTests.cpp +++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp @@ -581,7 +581,7 @@ RENDERTHREAD_TEST(FrameBuilder, functor_reject) { auto scrolledFunctorView = TestUtils::createNode(0, 0, 400, 1000000, [&noopFunctor](RenderProperties& props, RecordingCanvas& canvas) { canvas.translate(0, -800000); - canvas.callDrawGLFunction(&noopFunctor); + canvas.callDrawGLFunction(&noopFunctor, nullptr); }); FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, diff --git a/libs/hwui/tests/unit/RenderNodeTests.cpp b/libs/hwui/tests/unit/RenderNodeTests.cpp index 7c57a50c951d..b2997dfb357f 100644 --- a/libs/hwui/tests/unit/RenderNodeTests.cpp +++ b/libs/hwui/tests/unit/RenderNodeTests.cpp @@ -51,3 +51,41 @@ TEST(RenderNode, hasParents) { EXPECT_FALSE(child->hasParents()) << "Child should be removed"; EXPECT_FALSE(parent->hasParents()) << "Root node shouldn't have any parents"; } + +TEST(RenderNode, releasedCallback) { + class DecRefOnReleased : public GlFunctorLifecycleListener { + public: + DecRefOnReleased(int* refcnt) : mRefCnt(refcnt) {} + void onGlFunctorReleased(Functor* functor) override { + *mRefCnt -= 1; + } + private: + int* mRefCnt; + }; + + int refcnt = 0; + sp<DecRefOnReleased> listener(new DecRefOnReleased(&refcnt)); + Functor noopFunctor; + + auto node = TestUtils::createNode(0, 0, 200, 400, + [&](RenderProperties& props, TestCanvas& canvas) { + refcnt++; + canvas.callDrawGLFunction(&noopFunctor, listener.get()); + }); + TestUtils::syncHierarchyPropertiesAndDisplayList(node); + EXPECT_EQ(1, refcnt); + + TestUtils::recordNode(*node, [&](TestCanvas& canvas) { + refcnt++; + canvas.callDrawGLFunction(&noopFunctor, listener.get()); + }); + EXPECT_EQ(2, refcnt); + + TestUtils::syncHierarchyPropertiesAndDisplayList(node); + EXPECT_EQ(1, refcnt); + + TestUtils::recordNode(*node, [](TestCanvas& canvas) {}); + EXPECT_EQ(1, refcnt); + TestUtils::syncHierarchyPropertiesAndDisplayList(node); + EXPECT_EQ(0, refcnt); +} diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java index 7c6adadc2c6a..2cd98721bd41 100644 --- a/media/java/android/media/browse/MediaBrowser.java +++ b/media/java/android/media/browse/MediaBrowser.java @@ -27,6 +27,7 @@ import android.content.pm.ParceledListSlice; import android.media.MediaDescription; import android.media.session.MediaController; import android.media.session.MediaSession; +import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -475,14 +476,8 @@ public final class MediaBrowser { // the service will be told when we connect. if (mState == CONNECT_STATE_CONNECTED) { try { - // NOTE: Do not call addSubscriptionWithOptions when options are null. Otherwise, - // it will break the action of support library which expects addSubscription will - // be called when options are null. - if (options == null) { - mServiceBinder.addSubscription(parentId, mServiceCallbacks); - } else { - mServiceBinder.addSubscriptionWithOptions(parentId, options, mServiceCallbacks); - } + mServiceBinder.addSubscription(parentId, callback.mToken, options, + mServiceCallbacks); } catch (RemoteException ex) { // Process is crashing. We will disconnect, and upon reconnect we will // automatically reregister. So nothing to do here. @@ -497,34 +492,37 @@ public final class MediaBrowser { throw new IllegalArgumentException("parentId is empty."); } - // Remove from our list. Subscription sub = mSubscriptions.get(parentId); - + if (sub == null) { + return; + } // Tell the service if necessary. - if (mState == CONNECT_STATE_CONNECTED && sub != null) { - try { - if (callback == null) { - mServiceBinder.removeSubscription(parentId, mServiceCallbacks); - } else { - final List<SubscriptionCallback> callbacks = sub.getCallbacks(); - final List<Bundle> optionsList = sub.getOptionsList(); - for (int i = callbacks.size() - 1; i >= 0; --i) { - if (callbacks.get(i) == callback) { - mServiceBinder.removeSubscriptionWithOptions( - parentId, optionsList.get(i), mServiceCallbacks); - callbacks.remove(i); - optionsList.remove(i); + try { + if (callback == null) { + if (mState == CONNECT_STATE_CONNECTED) { + mServiceBinder.removeSubscription(parentId, null, mServiceCallbacks); + } + } else { + final List<SubscriptionCallback> callbacks = sub.getCallbacks(); + final List<Bundle> optionsList = sub.getOptionsList(); + for (int i = callbacks.size() - 1; i >= 0; --i) { + if (callbacks.get(i) == callback) { + if (mState == CONNECT_STATE_CONNECTED) { + mServiceBinder.removeSubscription( + parentId, callback.mToken, mServiceCallbacks); } + callbacks.remove(i); + optionsList.remove(i); } } - } catch (RemoteException ex) { - // Process is crashing. We will disconnect, and upon reconnect we will - // automatically reregister. So nothing to do here. - Log.d(TAG, "removeSubscription failed with RemoteException parentId=" + parentId); } + } catch (RemoteException ex) { + // Process is crashing. We will disconnect, and upon reconnect we will + // automatically reregister. So nothing to do here. + Log.d(TAG, "removeSubscription failed with RemoteException parentId=" + parentId); } - if (sub != null && (sub.isEmpty() || callback == null)) { + if (sub.isEmpty() || callback == null) { mSubscriptions.remove(parentId); } } @@ -579,17 +577,12 @@ public final class MediaBrowser { for (Entry<String, Subscription> subscriptionEntry : mSubscriptions.entrySet()) { String id = subscriptionEntry.getKey(); Subscription sub = subscriptionEntry.getValue(); - for (Bundle options : sub.getOptionsList()) { + List<SubscriptionCallback> callbackList = sub.getCallbacks(); + List<Bundle> optionsList = sub.getOptionsList(); + for (int i = 0; i < callbackList.size(); ++i) { try { - // NOTE: Do not call addSubscriptionWithOptions when options are null. - // Otherwise, it will break the action of support library which expects - // addSubscription will be called when options are null. - if (options == null) { - mServiceBinder.addSubscription(id, mServiceCallbacks); - } else { - mServiceBinder.addSubscriptionWithOptions( - id, options, mServiceCallbacks); - } + mServiceBinder.addSubscription(id, callbackList.get(i).mToken, + optionsList.get(i), mServiceCallbacks); } catch (RemoteException ex) { // Process is crashing. We will disconnect, and upon reconnect we will // automatically reregister. So nothing to do here. @@ -859,6 +852,12 @@ public final class MediaBrowser { * Callbacks for subscription related events. */ public static abstract class SubscriptionCallback { + Binder mToken; + + public SubscriptionCallback() { + mToken = new Binder(); + } + /** * Called when the list of children is loaded or updated. * @@ -1071,12 +1070,7 @@ public final class MediaBrowser { } @Override - public void onLoadChildren(String parentId, ParceledListSlice list) { - onLoadChildrenWithOptions(parentId, list, null); - } - - @Override - public void onLoadChildrenWithOptions(String parentId, ParceledListSlice list, + public void onLoadChildren(String parentId, ParceledListSlice list, final Bundle options) { MediaBrowser mediaBrowser = mMediaBrowser.get(); if (mediaBrowser != null) { diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java index e1346351ba98..21211d74b246 100644 --- a/media/java/android/media/tv/TvInputService.java +++ b/media/java/android/media/tv/TvInputService.java @@ -839,9 +839,11 @@ public abstract class TvInputService extends Service { public abstract boolean onTune(Uri channelUri); /** - * Calls {@link #onTune(Uri)}. Override this method in order to handle domain-specific + * Tunes to a given channel. Override this method in order to handle domain-specific * features that are only known between certain TV inputs and their clients. * + * <p>The default implementation calls {@link #onTune(Uri)}. + * * @param channelUri The URI of the channel. * @param params Domain-specific data for this tune request. Keys <em>must</em> be a scoped * name, i.e. prefixed with a package name you own, so that different developers @@ -1693,11 +1695,12 @@ public abstract class TvInputService extends Service { public abstract void onTune(Uri channelUri); /** - * Calls {@link #onTune(Uri)}. Override this method in order to handle domain-specific - * features that are only known between certain TV inputs and their clients. + * Called when the application requests to tune to a given channel for TV program recording. + * Override this method in order to handle domain-specific features that are only known + * between certain TV inputs and their clients. * * <p>The application may call this method before starting or after stopping recording, but - * not during recording. + * not during recording. The default implementation calls {@link #onTune(Uri)}. * * <p>The session must call {@link #notifyTuned(Uri)} if the tune request was fulfilled, or * {@link #notifyError(int)} otherwise. diff --git a/media/java/android/service/media/IMediaBrowserService.aidl b/media/java/android/service/media/IMediaBrowserService.aidl index 6ca5ac59369f..eef5a7ccecad 100644 --- a/media/java/android/service/media/IMediaBrowserService.aidl +++ b/media/java/android/service/media/IMediaBrowserService.aidl @@ -14,19 +14,11 @@ import android.os.ResultReceiver; * @hide */ oneway interface IMediaBrowserService { - - // Warning: DO NOT CHANGE the methods signature and order of methods. - // A change of the order or the method signatures could break the support library. - void connect(String pkg, in Bundle rootHints, IMediaBrowserServiceCallbacks callbacks); void disconnect(IMediaBrowserServiceCallbacks callbacks); - void addSubscription(String uri, IMediaBrowserServiceCallbacks callbacks); - void removeSubscription(String uri, IMediaBrowserServiceCallbacks callbacks); - void getMediaItem(String uri, in ResultReceiver cb); - - void addSubscriptionWithOptions(String uri, in Bundle options, - IMediaBrowserServiceCallbacks callbacks); - void removeSubscriptionWithOptions(String uri, in Bundle options, + void addSubscription(String uri, in IBinder token, in Bundle options, IMediaBrowserServiceCallbacks callbacks); + void removeSubscription(String uri, in IBinder token, IMediaBrowserServiceCallbacks callbacks); + void getMediaItem(String uri, in ResultReceiver cb); } diff --git a/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl b/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl index e6b0e8cfbb13..dadb025060b7 100644 --- a/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl +++ b/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl @@ -13,10 +13,6 @@ import android.os.Bundle; * @hide */ oneway interface IMediaBrowserServiceCallbacks { - - // Warning: DO NOT CHANGE the methods signature and order of methods. - // A change of the order or the method signatures could break the support library. - /** * Invoked when the connected has been established. * @param root The root media id for browsing. @@ -26,6 +22,5 @@ oneway interface IMediaBrowserServiceCallbacks { */ void onConnect(String root, in MediaSession.Token session, in Bundle extras); void onConnectFailed(); - void onLoadChildren(String mediaId, in ParceledListSlice list); - void onLoadChildrenWithOptions(String mediaId, in ParceledListSlice list, in Bundle options); + void onLoadChildren(String mediaId, in ParceledListSlice list, in Bundle options); } diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java index 6954045574a5..ddc0e882f9f5 100644 --- a/media/java/android/service/media/MediaBrowserService.java +++ b/media/java/android/service/media/MediaBrowserService.java @@ -39,6 +39,7 @@ import android.service.media.IMediaBrowserServiceCallbacks; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; +import android.util.Pair; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -108,7 +109,7 @@ public abstract class MediaBrowserService extends Service { Bundle rootHints; IMediaBrowserServiceCallbacks callbacks; BrowserRoot root; - HashMap<String, List<Bundle>> subscriptions = new HashMap<>(); + HashMap<String, List<Pair<IBinder, Bundle>>> subscriptions = new HashMap<>(); } /** @@ -247,13 +248,7 @@ public abstract class MediaBrowserService extends Service { } @Override - public void addSubscription(final String id, - final IMediaBrowserServiceCallbacks callbacks) { - addSubscriptionWithOptions(id, null, callbacks); - } - - @Override - public void addSubscriptionWithOptions(final String id, final Bundle options, + public void addSubscription(final String id, final IBinder token, final Bundle options, final IMediaBrowserServiceCallbacks callbacks) { mHandler.post(new Runnable() { @Override @@ -268,19 +263,13 @@ public abstract class MediaBrowserService extends Service { return; } - MediaBrowserService.this.addSubscription(id, connection, options); + MediaBrowserService.this.addSubscription(id, connection, token, options); } }); } @Override - public void removeSubscription(final String id, - final IMediaBrowserServiceCallbacks callbacks) { - removeSubscriptionWithOptions(id, null, callbacks); - } - - @Override - public void removeSubscriptionWithOptions(final String id, final Bundle options, + public void removeSubscription(final String id, final IBinder token, final IMediaBrowserServiceCallbacks callbacks) { mHandler.post(new Runnable() { @Override @@ -293,7 +282,7 @@ public abstract class MediaBrowserService extends Service { + id); return; } - if (!MediaBrowserService.this.removeSubscription(id, connection, options)) { + if (!MediaBrowserService.this.removeSubscription(id, connection, token)) { Log.w(TAG, "removeSubscription called for " + id + " which is not subscribed"); } @@ -519,11 +508,12 @@ public abstract class MediaBrowserService extends Service { public void run() { for (IBinder binder : mConnections.keySet()) { ConnectionRecord connection = mConnections.get(binder); - List<Bundle> optionsList = connection.subscriptions.get(parentId); - if (optionsList != null) { - for (Bundle bundle : optionsList) { - if (MediaBrowserUtils.hasDuplicatedItems(options, bundle)) { - performLoadChildren(parentId, connection, bundle); + List<Pair<IBinder, Bundle>> callbackList = + connection.subscriptions.get(parentId); + if (callbackList != null) { + for (Pair<IBinder, Bundle> callback : callbackList) { + if (MediaBrowserUtils.hasDuplicatedItems(options, callback.second)) { + performLoadChildren(parentId, connection, callback.second); } } } @@ -553,19 +543,21 @@ public abstract class MediaBrowserService extends Service { /** * Save the subscription and if it is a new subscription send the results. */ - private void addSubscription(String id, ConnectionRecord connection, Bundle options) { + private void addSubscription(String id, ConnectionRecord connection, IBinder token, + Bundle options) { // Save the subscription - List<Bundle> optionsList = connection.subscriptions.get(id); - if (optionsList == null) { - optionsList = new ArrayList<>(); + List<Pair<IBinder, Bundle>> callbackList = connection.subscriptions.get(id); + if (callbackList == null) { + callbackList = new ArrayList<>(); } - for (Bundle bundle : optionsList) { - if (MediaBrowserUtils.areSameOptions(options, bundle)) { + for (Pair<IBinder, Bundle> callback : callbackList) { + if (token == callback.first + && MediaBrowserUtils.areSameOptions(options, callback.second)) { return; } } - optionsList.add(options); - connection.subscriptions.put(id, optionsList); + callbackList.add(new Pair<>(token, options)); + connection.subscriptions.put(id, callbackList); // send the results performLoadChildren(id, connection, options); } @@ -573,21 +565,20 @@ public abstract class MediaBrowserService extends Service { /** * Remove the subscription. */ - private boolean removeSubscription(String id, ConnectionRecord connection, Bundle options) { - if (options == null) { + private boolean removeSubscription(String id, ConnectionRecord connection, IBinder token) { + if (token == null) { return connection.subscriptions.remove(id) != null; } boolean removed = false; - List<Bundle> optionsList = connection.subscriptions.get(id); - if (optionsList != null) { - for (Bundle bundle : optionsList) { - if (MediaBrowserUtils.areSameOptions(options, bundle)) { + List<Pair<IBinder, Bundle>> callbackList = connection.subscriptions.get(id); + if (callbackList != null) { + for (Pair<IBinder, Bundle> callback : callbackList) { + if (token == callback.first) { removed = true; - optionsList.remove(bundle); - break; + callbackList.remove(callback); } } - if (optionsList.size() == 0) { + if (callbackList.size() == 0) { connection.subscriptions.remove(id); } } @@ -619,14 +610,7 @@ public abstract class MediaBrowserService extends Service { final ParceledListSlice<MediaBrowser.MediaItem> pls = filteredList == null ? null : new ParceledListSlice<>(filteredList); try { - // NOTE: Do not call onLoadChildrenWithOptions when options are null. Otherwise, - // it will break the action of support library which expects onLoadChildren will - // be called when options are null. - if (options == null) { - connection.callbacks.onLoadChildren(parentId, pls); - } else { - connection.callbacks.onLoadChildrenWithOptions(parentId, pls, options); - } + connection.callbacks.onLoadChildren(parentId, pls, options); } catch (RemoteException ex) { // The other side is in the process of crashing. Log.w(TAG, "Calling onLoadChildren() failed for id=" + parentId diff --git a/packages/SettingsLib/res/drawable/notification_auto_importance.xml b/packages/SettingsLib/res/drawable/notification_auto_importance.xml new file mode 100644 index 000000000000..a63e911b9ffc --- /dev/null +++ b/packages/SettingsLib/res/drawable/notification_auto_importance.xml @@ -0,0 +1,27 @@ +<!-- + Copyright (C) 2016 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.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M11.2,13.6l1.6,0l-0.8,-2.6z"/> + <path + android:fillColor="#FF000000" + android:pathData="M22.5,9.6L15,9l-3,-7L9,9L1.5,9.6l5.7,5L5.5,22l6.5,-3.9l6.5,3.9l-1.7,-7.4L22.5,9.6zM13.6,16l-0.5,-1.4h-2.3L10.4,16H9l2.3,-6.4h1.4L15,16H13.6z"/> +</vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml index 062ae35d2750..e1424f0cb7e5 100644 --- a/packages/SystemUI/res/layout/notification_guts.xml +++ b/packages/SystemUI/res/layout/notification_guts.xml @@ -32,7 +32,7 @@ <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingTop="14dp" + android:paddingTop="15dp" android:paddingEnd="8dp" android:id="@+id/notification_guts_header" android:orientation="horizontal" @@ -99,6 +99,7 @@ android:clickable="false" android:focusable="false" android:paddingEnd="8dp" + android:paddingTop="4dp" android:visibility="gone"> <TextView android:id="@+id/title" @@ -123,21 +124,20 @@ <FrameLayout android:layout_width="match_parent" - android:layout_height="48dp" + android:layout_height="wrap_content" android:paddingTop="8dp" > <ImageView - android:id="@+id/low_importance" - android:src="@*android:drawable/ic_notification_block" + android:id="@+id/auto_importance" + android:src="@drawable/notification_auto_importance" android:layout_gravity="center_vertical|start" - android:layout_width="24dp" - android:layout_height="24dp" - android:tint="@color/notification_guts_icon_tint"/> + android:layout_width="48dp" + android:layout_height="48dp" /> <SeekBar android:id="@+id/seekbar" android:layout_marginStart="56dp" - android:layout_marginEnd="56dp" + android:layout_marginEnd="32dp" android:layout_gravity="center_vertical" android:layout_width="match_parent" android:layout_height="48dp" @@ -149,14 +149,6 @@ style="@android:style/Widget.Material.SeekBar.Discrete" android:tickMarkTint="@android:color/black" /> - <ImageView - android:id="@+id/max_importance" - android:src="@*android:drawable/ic_notification_alert" - android:layout_gravity="center_vertical|end" - android:layout_width="24dp" - android:layout_height="24dp" - android:tint="@color/notification_guts_icon_tint" /> - </FrameLayout> </LinearLayout> <!-- buttons --> diff --git a/packages/SystemUI/res/layout/power_notification_controls_settings.xml b/packages/SystemUI/res/layout/power_notification_controls_settings.xml new file mode 100644 index 000000000000..83c8a51f6330 --- /dev/null +++ b/packages/SystemUI/res/layout/power_notification_controls_settings.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2016 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="match_parent" + android:orientation="vertical"> + + <include layout="@layout/switch_bar" /> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="16dp" + android:text="@string/power_notification_controls_description"/> + +</LinearLayout> diff --git a/packages/SystemUI/res/layout/recents_task_view_header.xml b/packages/SystemUI/res/layout/recents_task_view_header.xml index 2df57bfbd55b..5ee242dc314c 100644 --- a/packages/SystemUI/res/layout/recents_task_view_header.xml +++ b/packages/SystemUI/res/layout/recents_task_view_header.xml @@ -43,7 +43,8 @@ android:singleLine="true" android:maxLines="1" android:ellipsize="marquee" - android:fadingEdge="horizontal" /> + android:fadingEdge="horizontal" + android:forceHasOverlappingRendering="false" /> <com.android.systemui.recents.views.FixedSizeImageView android:id="@+id/move_task" android:layout_width="wrap_content" diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index d26fb061bb24..c75741c1d487 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -108,6 +108,7 @@ <!-- The "inside" of a notification, reached via longpress --> <color name="notification_guts_bg_color">#eeeeee</color> <color name="notification_guts_slider_color">@*android:color/material_deep_teal_500</color> + <color name="notification_guts_disabled_slider_color">@*android:color/material_grey_300</color> <color name="notification_guts_secondary_slider_color">#858383</color> <color name="notification_guts_icon_tint">#8a000000</color> <color name="notification_guts_disabled_icon_tint">#4d000000</color> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index a4d7a18e0505..37b00bbfdc27 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1225,38 +1225,69 @@ <string name="do_not_silence_block">Don\'t silence or block</string> <!-- [CHAR LIMIT=NONE] Importance Tuner setting title --> - <string name="tuner_full_importance_settings">Show full importance settings</string> + <string name="tuner_full_importance_settings">Power notification controls</string> + <string name="tuner_full_importance_settings_on">On</string> + <string name="tuner_full_importance_settings_off">Off</string> + <string name="power_notification_controls_description">With power notification controls, you can set an importance level from 0 to 5 for an app\'s notifications. + \n\n<b>Level 5</b> + \n- Show at the top of the notification list + \n- Allow full screen interruption + \n- Always peek + \n\n<b>Level 4</b> + \n- Prevent full screen interruption + \n- Always peek + \n\n<b>Level 3</b> + \n- Prevent full screen interruption + \n- Never peek + \n\n<b>Level 2</b> + \n- Prevent full screen interruption + \n- Never peek + \n- Never make sound and vibration + \n\n<b>Level 1</b> + \n- Prevent full screen interruption + \n- Never peek + \n- Never make sound or vibrate + \n- Hide from lock screen and status bar + \n- Show at the bottom of the notification list + \n\n<b>Level 0</b> + \n- Block all notifications from the app + </string> + <!-- Notification importance title, user unspecified status--> + <string name="user_unspecified_importance">Importance: Automatic</string> <!-- Notification importance title, blocked status--> - <string name="blocked_importance">Blocked</string> + <string name="blocked_importance">Importance: Level 0</string> <!-- Notification importance title, min status--> - <string name="min_importance">Min importance</string> + <string name="min_importance">Importance: Level 1</string> <!-- Notification importance title, low status--> - <string name="low_importance">Low importance</string> + <string name="low_importance">Importance: Level 2</string> <!-- Notification importance title, normal status--> - <string name="default_importance">Normal importance</string> + <string name="default_importance">Importance: Level 3</string> <!-- Notification importance title, high status--> - <string name="high_importance">High importance</string> + <string name="high_importance">Importance: Level 4</string> <!-- Notification importance title, max status--> - <string name="max_importance">Urgent importance</string> + <string name="max_importance">Importance: Level 5</string> + + <!-- [CHAR LIMIT=100] Notification Importance slider: blocked importance level description --> + <string name="notification_importance_user_unspecified">App determines importance for each notification.</string> <!-- [CHAR LIMIT=100] Notification Importance slider: blocked importance level description --> - <string name="notification_importance_blocked">Never show these notifications</string> + <string name="notification_importance_blocked">Never show notifications from this app.</string> <!-- [CHAR LIMIT=100] Notification Importance slider: min importance level description --> - <string name="notification_importance_min">Silently show at the bottom of the notification list</string> + <string name="notification_importance_min">No full screen interruption, peeking, sound, or vibration. Hide from lock screen and status bar.</string> <!-- [CHAR LIMIT=100] Notification Importance slider: low importance level description --> - <string name="notification_importance_low">Silently show these notifications</string> + <string name="notification_importance_low">No full screen interruption, peeking, sound, or vibration.</string> <!-- [CHAR LIMIT=100] Notification Importance slider: normal importance level description --> - <string name="notification_importance_default">Allow these notification to make sounds</string> + <string name="notification_importance_default">No full screen interruption or peeking.</string> <!-- [CHAR LIMIT=100] Notification Importance slider: high importance level description --> - <string name="notification_importance_high">Peek onto the screen and allow sound and allow sound</string> + <string name="notification_importance_high">Always peek. No full screen interruption.</string> <!-- [CHAR LIMIT=100] Notification Importance slider: max importance level description --> - <string name="notification_importance_max">Show at the top of the notifications list, peek onto the screen and allow sound</string> + <string name="notification_importance_max">Always peek, and allow full screen interruption.</string> <!-- Notification: Control panel: Label for button that launches notification settings. [CHAR LIMIT=NONE] --> <string name="notification_more_settings">More settings</string> diff --git a/packages/SystemUI/res/xml/other_settings.xml b/packages/SystemUI/res/xml/other_settings.xml new file mode 100644 index 000000000000..3c872fa98bc7 --- /dev/null +++ b/packages/SystemUI/res/xml/other_settings.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2016 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. +--> + +<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:sysui="http://schemas.android.com/apk/res-auto" + android:title="@string/other"> + + <com.android.systemui.tuner.TunerSwitch + android:key="overview_nav_bar_gesture" + android:title="@string/overview_nav_bar_gesture" + android:summary="@string/overview_nav_bar_gesture_desc" /> + + <!-- importance --> + <Preference + android:key="power_notification_controls" + android:title="@string/tuner_full_importance_settings" + android:fragment="com.android.systemui.tuner.PowerNotificationControlsFragment"/> + +</PreferenceScreen>
\ No newline at end of file diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml index 1af9075a4e16..116bc69fd0d4 100644 --- a/packages/SystemUI/res/xml/tuner_prefs.xml +++ b/packages/SystemUI/res/xml/tuner_prefs.xml @@ -135,21 +135,10 @@ android:fragment="com.android.systemui.tuner.NavBarTuner" /> --> - <PreferenceScreen - android:key="other" - android:title="@string/other" > - - <com.android.systemui.tuner.TunerSwitch - android:key="overview_nav_bar_gesture" - android:title="@string/overview_nav_bar_gesture" - android:summary="@string/overview_nav_bar_gesture_desc" /> - - <!-- importance --> - <com.android.systemui.tuner.TunerSwitch - android:key="show_importance_slider" - android:title="@string/tuner_full_importance_settings" /> - - </PreferenceScreen> + <Preference + android:key="other" + android:title="@string/other" + android:fragment="com.android.systemui.tuner.OtherPrefs" /> <!-- Warning, this goes last. --> <Preference diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 1abd073e4772..4d8e33d1a6a1 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -1215,7 +1215,6 @@ public class KeyguardViewMediator extends SystemUI { private void lockProfile(int userId) { mTrustManager.setDeviceLockedForUser(userId, true); - notifyLockedProfile(userId); } private boolean shouldWaitForProvisioning() { @@ -1546,13 +1545,6 @@ public class KeyguardViewMediator extends SystemUI { } } - private void notifyLockedProfile(@UserIdInt int userId) { - try { - ActivityManagerNative.getDefault().notifyLockedProfile(userId); - } catch (RemoteException e) { - } - } - /** * Handle message sent by {@link #showLocked}. * @see #SHOW diff --git a/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl b/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl index 9a00d95d6060..1240e055d25a 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl +++ b/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl @@ -27,7 +27,7 @@ oneway interface IRecentsSystemUserCallbacks { void registerNonSystemUserCallbacks(IBinder nonSystemUserCallbacks, int userId); void updateRecentsVisibility(boolean visible); - void startScreenPinning(); + void startScreenPinning(int taskId); void sendRecentsDrawnEvent(); void sendDockingTopTaskEvent(int dragMode, in Rect initialRect); void sendLaunchRecentsEvent(); diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java index b2d7b4866fae..a227e1d00011 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java @@ -598,13 +598,13 @@ public class Recents extends SystemUI public final void onBusEvent(final ScreenPinningRequestEvent event) { int processUser = sSystemServicesProxy.getProcessUser(); if (sSystemServicesProxy.isSystemUser(processUser)) { - mImpl.onStartScreenPinning(event.applicationContext); + mImpl.onStartScreenPinning(event.applicationContext, event.taskId); } else { postToSystemUser(new Runnable() { @Override public void run() { try { - mUserToSystemCallbacks.startScreenPinning(); + mUserToSystemCallbacks.startScreenPinning(event.taskId); } catch (RemoteException e) { Log.e(TAG, "Callback failed", e); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java index c230cd8fa400..618a2e2c485b 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java @@ -221,11 +221,11 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener * visibility change events through to the system user via * {@link Recents#onBusEvent(ScreenPinningRequestEvent)}. */ - public void onStartScreenPinning(Context context) { + public void onStartScreenPinning(Context context, int taskId) { SystemUIApplication app = (SystemUIApplication) context; PhoneStatusBar statusBar = app.getComponent(PhoneStatusBar.class); if (statusBar != null) { - statusBar.showScreenPinningRequest(false); + statusBar.showScreenPinningRequest(taskId, false); } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java index ffeb4a10b050..913da185c40d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java @@ -82,8 +82,8 @@ public class RecentsSystemUser extends IRecentsSystemUserCallbacks.Stub { } @Override - public void startScreenPinning() { - mImpl.onStartScreenPinning(mContext); + public void startScreenPinning(int taskId) { + mImpl.onStartScreenPinning(mContext, taskId); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java index 13d4acb370a3..7a604cace2dc 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java +++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java @@ -52,6 +52,9 @@ public class ScreenPinningRequest implements View.OnClickListener { private RequestWindowView mRequestWindow; + // Id of task to be pinned or locked. + private int taskId; + public ScreenPinningRequest(Context context) { mContext = context; mAccessibilityService = (AccessibilityManager) @@ -67,9 +70,11 @@ public class ScreenPinningRequest implements View.OnClickListener { } } - public void showPrompt(boolean allowCancel) { + public void showPrompt(int taskId, boolean allowCancel) { clearPrompt(); + this.taskId = taskId; + mRequestWindow = new RequestWindowView(mContext, allowCancel); mRequestWindow.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE); @@ -106,7 +111,7 @@ public class ScreenPinningRequest implements View.OnClickListener { public void onClick(View v) { if (v.getId() == R.id.screen_pinning_ok_button || mRequestWindow == v) { try { - ActivityManagerNative.getDefault().startLockTaskModeOnCurrent(); + ActivityManagerNative.getDefault().startSystemLockTaskMode(taskId); } catch (RemoteException e) {} } clearPrompt(); diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/component/ScreenPinningRequestEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/component/ScreenPinningRequestEvent.java index 75e459a0946c..d460917b6ab4 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/component/ScreenPinningRequestEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/component/ScreenPinningRequestEvent.java @@ -26,8 +26,10 @@ import com.android.systemui.recents.events.EventBus; public class ScreenPinningRequestEvent extends EventBus.Event { public final Context applicationContext; + public final int taskId; - public ScreenPinningRequestEvent(Context context) { + public ScreenPinningRequestEvent(Context context, int taskId) { this.applicationContext = context.getApplicationContext(); + this.taskId = taskId; } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java index fd8df991b399..db5413f85c24 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java @@ -77,12 +77,17 @@ public class RecentsTransitionHelper { private Handler mHandler; private TaskViewTransform mTmpTransform = new TaskViewTransform(); - private Runnable mStartScreenPinningRunnable = new Runnable() { + private class StartScreenPinningRunnableRunnable implements Runnable { + + private int taskId = -1; + @Override public void run() { - EventBus.getDefault().send(new ScreenPinningRequestEvent(mContext)); + EventBus.getDefault().send(new ScreenPinningRequestEvent(mContext, taskId)); } - }; + } + private StartScreenPinningRunnableRunnable mStartScreenPinningRunnable + = new StartScreenPinningRunnableRunnable(); public RecentsTransitionHelper(Context context) { mContext = context; @@ -120,6 +125,7 @@ public class RecentsTransitionHelper { if (screenPinningRequested) { // Request screen pinning after the animation runs + mStartScreenPinningRunnable.taskId = task.key.id; mHandler.postDelayed(mStartScreenPinningRunnable, 350); } } diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java index 2bf0b4012cd7..5d1a61d4bd5d 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java @@ -39,6 +39,7 @@ public class Divider extends SystemUI { private DockDividerVisibilityListener mDockDividerVisibilityListener; private boolean mVisible = false; private boolean mMinimized = false; + private boolean mAdjustedForIme = false; private ForcedResizableInfoActivityController mForcedResizableController; @Override @@ -84,7 +85,7 @@ public class Divider extends SystemUI { addDivider(configuration); if (mMinimized) { mView.setMinimizedDockStack(true); - mWindowManager.setTouchable(false); + updateTouchable(); } } @@ -109,7 +110,7 @@ public class Divider extends SystemUI { public void run() { if (mMinimized != minimized) { mMinimized = minimized; - mWindowManager.setTouchable(!minimized); + updateTouchable(); if (animDuration > 0) { mView.setMinimizedDockStack(minimized, animDuration); } else { @@ -129,6 +130,10 @@ public class Divider extends SystemUI { }); } + private void updateTouchable() { + mWindowManager.setTouchable(!mMinimized && !mAdjustedForIme); + } + class DockDividerVisibilityListener extends IDockedStackListener.Stub { @Override @@ -148,6 +153,22 @@ public class Divider extends SystemUI { } @Override + public void onAdjustedForImeChanged(boolean adjustedForIme, long animDuration) + throws RemoteException { + mView.post(() -> { + if (mAdjustedForIme != adjustedForIme) { + mAdjustedForIme = adjustedForIme; + updateTouchable(); + if (animDuration > 0) { + mView.setAdjustedForIme(adjustedForIme, animDuration); + } else { + mView.setAdjustedForIme(adjustedForIme); + } + } + }); + } + + @Override public void onDockSideChanged(final int newDockSide) throws RemoteException { mView.post(() -> mView.notifyDockSideChanged(newDockSide)); } diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java index 66a413cf7ca5..4d1c6ba36737 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java @@ -31,7 +31,6 @@ import android.graphics.Rect; import android.graphics.Region.Op; import android.hardware.display.DisplayManager; import android.os.Bundle; -import android.os.Vibrator; import android.util.AttributeSet; import android.view.Display; import android.view.DisplayInfo; @@ -61,7 +60,6 @@ import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget; import com.android.internal.policy.DockedDividerUtils; import com.android.systemui.Interpolators; import com.android.systemui.R; -import com.android.systemui.recents.Constants.Metrics; import com.android.systemui.recents.Recents; import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.events.activity.DockedTopTaskEvent; @@ -98,6 +96,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, * How much the background gets scaled when we are in the minimized dock state. */ private static final float MINIMIZE_DOCK_SCALE = 0f; + private static final float ADJUSTED_FOR_IME_SCALE = 0.5f; private static final PathInterpolator SLOWDOWN_INTERPOLATOR = new PathInterpolator(0.5f, 1f, 0.5f, 1f); @@ -147,6 +146,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, private int mExitStartPosition; private GestureDetector mGestureDetector; private boolean mDockedStackMinimized; + private boolean mAdjustedForIme; private final AccessibilityDelegate mHandleDelegate = new AccessibilityDelegate() { @Override @@ -657,6 +657,40 @@ public class DividerView extends FrameLayout implements OnTouchListener, mDockedStackMinimized = minimized; } + public void setAdjustedForIme(boolean adjustedForIme) { + updateDockSide(); + mHandle.setAlpha(adjustedForIme ? 0f : 1f); + if (!adjustedForIme) { + resetBackground(); + } else if (mDockSide == WindowManager.DOCKED_TOP) { + mBackground.setPivotY(0); + mBackground.setScaleY(MINIMIZE_DOCK_SCALE); + } + mAdjustedForIme = adjustedForIme; + } + + public void setAdjustedForIme(boolean adjustedForIme, long animDuration) { + updateDockSide(); + mHandle.animate() + .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) + .setDuration(animDuration) + .alpha(adjustedForIme ? 0f : 1f) + .start(); + if (mDockSide == WindowManager.DOCKED_TOP) { + mBackground.setPivotY(0); + mBackground.animate() + .scaleY(adjustedForIme ? MINIMIZE_DOCK_SCALE : 1f); + } + if (!adjustedForIme) { + mBackground.animate().withEndAction(mResetBackgroundRunnable); + } + mBackground.animate() + .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) + .setDuration(animDuration) + .start(); + mAdjustedForIme = adjustedForIme; + } + private void resetBackground() { mBackground.setPivotX(mBackground.getWidth() / 2); mBackground.setPivotY(mBackground.getHeight() / 2); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index 99b63977b429..cc8e3bda99b4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -114,7 +114,7 @@ public class CommandQueue extends IStatusBar.Stub { void buzzBeepBlinked(); void notificationLightOff(); void notificationLightPulse(int argb, int onMillis, int offMillis); - void showScreenPinningRequest(); + void showScreenPinningRequest(int taskId); void appTransitionPending(); void appTransitionCancelled(); void appTransitionStarting(long startTime, long duration); @@ -298,9 +298,10 @@ public class CommandQueue extends IStatusBar.Stub { } } - public void showScreenPinningRequest() { + public void showScreenPinningRequest(int taskId) { synchronized (mLock) { - mHandler.sendEmptyMessage(MSG_SHOW_SCREEN_PIN_REQUEST); + mHandler.obtainMessage(MSG_SHOW_SCREEN_PIN_REQUEST, taskId, 0, null) + .sendToTarget(); } } @@ -450,7 +451,7 @@ public class CommandQueue extends IStatusBar.Stub { mCallbacks.notificationLightPulse((Integer) msg.obj, msg.arg1, msg.arg2); break; case MSG_SHOW_SCREEN_PIN_REQUEST: - mCallbacks.showScreenPinningRequest(); + mCallbacks.showScreenPinningRequest(msg.arg1); break; case MSG_APP_TRANSITION_PENDING: mCallbacks.appTransitionPending(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java index 3c464d5a1819..057b0204878b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java @@ -22,12 +22,14 @@ import android.app.INotificationManager; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.res.ColorStateList; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.RemoteException; import android.os.ServiceManager; import android.service.notification.NotificationListenerService; +import android.service.notification.NotificationListenerService.Ranking; import android.service.notification.StatusBarNotification; import android.util.AttributeSet; import android.view.View; @@ -60,10 +62,18 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab private int mActualHeight; private boolean mExposed; private INotificationManager mINotificationManager; - private int mStartingImportance; + private int mStartingUserImportance; + private int mNotificationImportance; private boolean mShowSlider; private SeekBar mSeekBar; + private ImageView mAutoButton; + private ColorStateList mActiveSliderTint; + private ColorStateList mInactiveSliderTint; + private TextView mImportanceSummary; + private TextView mImportanceTitle; + private boolean mAuto; + private RadioButton mBlock; private RadioButton mSilent; private RadioButton mReset; @@ -145,9 +155,14 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab void bindImportance(final PackageManager pm, final StatusBarNotification sbn, final ExpandableNotificationRow row, final int importance) { - mStartingImportance = importance; mINotificationManager = INotificationManager.Stub.asInterface( ServiceManager.getService(Context.NOTIFICATION_SERVICE)); + mStartingUserImportance = NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED; + try { + mStartingUserImportance = + mINotificationManager.getImportance(sbn.getPackageName(), sbn.getUid()); + } catch (RemoteException e) {} + mNotificationImportance = importance; boolean systemApp = false; try { final PackageInfo info = @@ -160,29 +175,25 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab final View importanceSlider = row.findViewById(R.id.importance_slider); final View importanceButtons = row.findViewById(R.id.importance_buttons); if (mShowSlider) { - bindSlider(importanceSlider, sbn, systemApp); + bindSlider(importanceSlider, systemApp); importanceSlider.setVisibility(View.VISIBLE); importanceButtons.setVisibility(View.GONE); } else { - mStartingImportance = NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED; - try { - mStartingImportance = - mINotificationManager.getImportance(sbn.getPackageName(), sbn.getUid()); - } catch (RemoteException e) {} - bindToggles(importanceButtons, mStartingImportance, systemApp); + + bindToggles(importanceButtons, mStartingUserImportance, systemApp); importanceButtons.setVisibility(View.VISIBLE); importanceSlider.setVisibility(View.GONE); } } public boolean hasImportanceChanged() { - return mStartingImportance != getSelectedImportance(); + return mStartingUserImportance != getSelectedImportance(); } void saveImportance(final StatusBarNotification sbn) { int progress = getSelectedImportance(); MetricsLogger.action(mContext, MetricsEvent.ACTION_SAVE_IMPORTANCE, - progress - mStartingImportance); + progress - mStartingUserImportance); try { mINotificationManager.setImportance(sbn.getPackageName(), sbn.getUid(), progress); } catch (RemoteException e) { @@ -192,14 +203,18 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab private int getSelectedImportance() { if (mSeekBar!= null && mSeekBar.isShown()) { - return mSeekBar.getProgress(); + if (mSeekBar.isEnabled()) { + return mSeekBar.getProgress(); + } else { + return Ranking.IMPORTANCE_UNSPECIFIED; + } } else { if (mBlock.isChecked()) { - return NotificationListenerService.Ranking.IMPORTANCE_NONE; + return Ranking.IMPORTANCE_NONE; } else if (mSilent.isChecked()) { - return NotificationListenerService.Ranking.IMPORTANCE_LOW; + return Ranking.IMPORTANCE_LOW; } else { - return NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED; + return Ranking.IMPORTANCE_UNSPECIFIED; } } } @@ -229,16 +244,14 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab } } - private void bindSlider(final View importanceSlider, final StatusBarNotification sbn, - final boolean systemApp) { - final TextView importanceSummary = ((TextView) importanceSlider.findViewById(R.id.summary)); - final TextView importanceTitle = ((TextView) importanceSlider.findViewById(R.id.title)); + private void bindSlider(final View importanceSlider, final boolean systemApp) { + mActiveSliderTint = loadColorStateList(R.color.notification_guts_slider_color); + mInactiveSliderTint = loadColorStateList(R.color.notification_guts_disabled_slider_color); + + mImportanceSummary = ((TextView) importanceSlider.findViewById(R.id.summary)); + mImportanceTitle = ((TextView) importanceSlider.findViewById(R.id.title)); mSeekBar = (SeekBar) importanceSlider.findViewById(R.id.seekbar); - if (systemApp) { - ((ImageView) importanceSlider.findViewById(R.id.low_importance)).getDrawable().setTint( - mContext.getColor(R.color.notification_guts_disabled_icon_tint)); - } final int minProgress = systemApp ? NotificationListenerService.Ranking.IMPORTANCE_MIN : NotificationListenerService.Ranking.IMPORTANCE_NONE; @@ -267,42 +280,80 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab // no-op } - private void updateTitleAndSummary(int progress) { - switch (progress) { - case NotificationListenerService.Ranking.IMPORTANCE_NONE: - importanceSummary.setText(mContext.getString( - R.string.notification_importance_blocked)); - importanceTitle.setText(mContext.getString(R.string.blocked_importance)); - break; - case NotificationListenerService.Ranking.IMPORTANCE_MIN: - importanceSummary.setText(mContext.getString( - R.string.notification_importance_min)); - importanceTitle.setText(mContext.getString(R.string.min_importance)); - break; - case NotificationListenerService.Ranking.IMPORTANCE_LOW: - importanceSummary.setText(mContext.getString( - R.string.notification_importance_low)); - importanceTitle.setText(mContext.getString(R.string.low_importance)); - break; - case NotificationListenerService.Ranking.IMPORTANCE_DEFAULT: - importanceSummary.setText(mContext.getString( - R.string.notification_importance_default)); - importanceTitle.setText(mContext.getString(R.string.default_importance)); - break; - case NotificationListenerService.Ranking.IMPORTANCE_HIGH: - importanceSummary.setText(mContext.getString( - R.string.notification_importance_high)); - importanceTitle.setText(mContext.getString(R.string.high_importance)); - break; - case NotificationListenerService.Ranking.IMPORTANCE_MAX: - importanceSummary.setText(mContext.getString( - R.string.notification_importance_max)); - importanceTitle.setText(mContext.getString(R.string.max_importance)); - break; - } + + }); + mSeekBar.setProgress(mNotificationImportance); + + mAutoButton = (ImageView) importanceSlider.findViewById(R.id.auto_importance); + mAutoButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + mAuto = !mAuto; + applyAuto(); } }); - mSeekBar.setProgress(mStartingImportance); + mAuto = mStartingUserImportance == Ranking.IMPORTANCE_UNSPECIFIED; + applyAuto(); + } + + private void applyAuto() { + mSeekBar.setEnabled(!mAuto); + + final ColorStateList tint = mAuto ? mInactiveSliderTint : mActiveSliderTint; + Drawable icon = mAutoButton.getDrawable().mutate(); + icon.setTintList(tint); + mAutoButton.setImageDrawable(icon); + mSeekBar.setProgressTintList(tint); + mSeekBar.setThumbTintList(tint); + + if (mAuto) { + mSeekBar.setProgress(mNotificationImportance); + mImportanceSummary.setText(mContext.getString( + R.string.notification_importance_user_unspecified)); + mImportanceTitle.setText(mContext.getString( + R.string.user_unspecified_importance)); + } else { + updateTitleAndSummary(mSeekBar.getProgress()); + } + } + + private void updateTitleAndSummary(int progress) { + switch (progress) { + case Ranking.IMPORTANCE_NONE: + mImportanceSummary.setText(mContext.getString( + R.string.notification_importance_blocked)); + mImportanceTitle.setText(mContext.getString(R.string.blocked_importance)); + break; + case Ranking.IMPORTANCE_MIN: + mImportanceSummary.setText(mContext.getString( + R.string.notification_importance_min)); + mImportanceTitle.setText(mContext.getString(R.string.min_importance)); + break; + case Ranking.IMPORTANCE_LOW: + mImportanceSummary.setText(mContext.getString( + R.string.notification_importance_low)); + mImportanceTitle.setText(mContext.getString(R.string.low_importance)); + break; + case Ranking.IMPORTANCE_DEFAULT: + mImportanceSummary.setText(mContext.getString( + R.string.notification_importance_default)); + mImportanceTitle.setText(mContext.getString(R.string.default_importance)); + break; + case Ranking.IMPORTANCE_HIGH: + mImportanceSummary.setText(mContext.getString( + R.string.notification_importance_high)); + mImportanceTitle.setText(mContext.getString(R.string.high_importance)); + break; + case Ranking.IMPORTANCE_MAX: + mImportanceSummary.setText(mContext.getString( + R.string.notification_importance_max)); + mImportanceTitle.setText(mContext.getString(R.string.max_importance)); + break; + } + } + + private ColorStateList loadColorStateList(int colorResId) { + return ColorStateList.valueOf(mContext.getColor(colorResId)); } public void closeControls(int x, int y, boolean notify) { @@ -353,7 +404,6 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab @Override public boolean hasOverlappingRendering() { - // Prevents this view from creating a layer when alpha is animating. return false; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java index 41eed565506d..951b09681c0b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileController.java @@ -15,6 +15,7 @@ package com.android.systemui.statusbar.phone; import android.app.ActivityManager; +import android.app.StatusBarManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -57,10 +58,18 @@ public class ManagedProfileController { } } - public void setWorkModeEnabled(boolean enabled) { + public void setWorkModeEnabled(boolean enableWorkMode) { synchronized (mProfiles) { for (UserInfo ui : mProfiles) { - mUserManager.setQuietModeEnabled(ui.id, !enabled); + if (enableWorkMode) { + if (!mUserManager.trySetQuietModeDisabled(ui.id, null)) { + StatusBarManager statusBarManager = (StatusBarManager) mContext + .getSystemService(android.app.Service.STATUS_BAR_SERVICE); + statusBarManager.collapsePanels(); + } + } else { + mUserManager.setQuietModeEnabled(ui.id, true); + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index d7fa5673e87a..4b7d56b27169 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -531,6 +531,11 @@ public class NavigationBarView extends LinearLayout { } @Override + public void onAdjustedForImeChanged(boolean adjustedForIme, long animDuration) + throws RemoteException { + } + + @Override public void onDockSideChanged(int newDockSide) throws RemoteException { } }); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index b6fc66b673c1..82806fdc6081 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -4323,7 +4323,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, try { IActivityManager activityManager = ActivityManagerNative.getDefault(); if (activityManager.isInLockTaskMode()) { - activityManager.stopLockTaskModeOnCurrent(); + activityManager.stopSystemLockTaskMode(); // When exiting refresh disabled flags. mNavigationBarView.setDisabledFlags(mDisabled1, true); @@ -4346,17 +4346,17 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } @Override - public void showScreenPinningRequest() { + public void showScreenPinningRequest(int taskId) { if (mKeyguardMonitor.isShowing()) { // Don't allow apps to trigger this from keyguard. return; } // Show screen pinning request, since this comes from an app, show 'no thanks', button. - showScreenPinningRequest(true); + showScreenPinningRequest(taskId, true); } - public void showScreenPinningRequest(boolean allowCancel) { - mScreenPinningRequest.showPrompt(allowCancel); + public void showScreenPinningRequest(int taskId, boolean allowCancel) { + mScreenPinningRequest.showPrompt(taskId, allowCancel); } public boolean hasActiveNotifications() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java index acef81b8ff1f..f9202c49d7e4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java @@ -165,7 +165,7 @@ public class TvStatusBar extends BaseStatusBar { } @Override - public void showScreenPinningRequest() { + public void showScreenPinningRequest(int taskId) { } @Override diff --git a/packages/SystemUI/src/com/android/systemui/tuner/OtherPrefs.java b/packages/SystemUI/src/com/android/systemui/tuner/OtherPrefs.java new file mode 100644 index 000000000000..205db323ba41 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/tuner/OtherPrefs.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2016 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.tuner; + +import android.os.Bundle; +import android.support.v14.preference.PreferenceFragment; +import com.android.systemui.R; + +public class OtherPrefs extends PreferenceFragment { + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + addPreferencesFromResource(R.xml.other_settings); + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/tuner/PowerNotificationControlsFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/PowerNotificationControlsFragment.java new file mode 100644 index 000000000000..14fccf21af43 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/tuner/PowerNotificationControlsFragment.java @@ -0,0 +1,93 @@ +/** + * Copyright (c) 2016, 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.tuner; + +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.MetricsProto.MetricsEvent; +import com.android.systemui.R; + +import android.annotation.Nullable; +import android.app.Fragment; +import android.os.Bundle; +import android.provider.Settings; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Switch; +import android.widget.TextView; + +public class PowerNotificationControlsFragment extends Fragment { + + private static final String KEY_SHOW_PNC = "show_importance_slider"; + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + return inflater.inflate(R.layout.power_notification_controls_settings, container, false); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + final View switchBar = view.findViewById(R.id.switch_bar); + final Switch switchWidget = (Switch) switchBar.findViewById(android.R.id.switch_widget); + final TextView switchText = (TextView) switchBar.findViewById(R.id.switch_text); + switchWidget.setChecked(isEnabled()); + switchText.setText(isEnabled() + ? getString(R.string.switch_bar_on) + : getString(R.string.switch_bar_off)); + + switchWidget.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + boolean newState = !isEnabled(); + MetricsLogger.action(getContext(), + MetricsEvent.ACTION_TUNER_POWER_NOTIFICATION_CONTROLS, newState); + Settings.Secure.putInt(getContext().getContentResolver(), + KEY_SHOW_PNC, newState ? 1 : 0); + switchWidget.setChecked(newState); + switchText.setText(newState + ? getString(R.string.switch_bar_on) + : getString(R.string.switch_bar_off)); + } + }); + } + + @Override + public void onResume() { + super.onResume(); + MetricsLogger.visibility( + getContext(), MetricsEvent.TUNER_POWER_NOTIFICATION_CONTROLS, true); + } + + @Override + public void onPause() { + super.onPause(); + MetricsLogger.visibility( + getContext(), MetricsEvent.TUNER_POWER_NOTIFICATION_CONTROLS, false); + } + + private boolean isEnabled() { + int setting = Settings.Secure.getInt(getContext().getContentResolver(), KEY_SHOW_PNC, 0); + return setting == 1; + } + +} diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index afea7f3aa980..7b3fd66f3236 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -2152,6 +2152,23 @@ message MetricsEvent { // User tried to dock an unresizable app. ACTION_WINDOW_DOCK_UNRESIZABLE = 391; + // System UI Tuner > Other > Power notification controls + TUNER_POWER_NOTIFICATION_CONTROLS = 392; + + // System UI Tuner > Other > Power notification controls > Toggle on/off + ACTION_TUNER_POWER_NOTIFICATION_CONTROLS = 393; + + // Action: user enable / disabled data saver using Settings. Arguments: + // 0: Data Saver mode is disabled. + // 1: Data Saver mode is enabled. + ACTION_DATA_SAVER_MODE = 394; + + // User whitelisted an app for Data Saver mode; action pass package name of app. + ACTION_DATA_SAVER_WHITELIST = 395; + + // User blacklisted an app for Data Saver mode; action pass package name of app. + ACTION_DATA_SAVER_BLACKLIST = 396; + // Add new aosp constants above this line. // END OF AOSP CONSTANTS } diff --git a/services/core/Android.mk b/services/core/Android.mk index 99c5dd69cda3..a248aa332225 100644 --- a/services/core/Android.mk +++ b/services/core/Android.mk @@ -4,11 +4,14 @@ include $(CLEAR_VARS) LOCAL_MODULE := services.core +LOCAL_AIDL_INCLUDES := system/netd/server/binder + LOCAL_SRC_FILES += \ $(call all-java-files-under,java) \ java/com/android/server/EventLogTags.logtags \ java/com/android/server/am/EventLogTags.logtags \ - ../../../../system/netd/server/binder/android/net/INetd.aidl + ../../../../system/netd/server/binder/android/net/INetd.aidl \ + ../../../../system/netd/server/binder/android/net/metrics/IDnsEventListener.aidl \ LOCAL_JAVA_LIBRARIES := services.net telephony-common LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java index f2b4e5218ac3..c1bacfaea7c6 100644 --- a/services/core/java/com/android/server/LockSettingsService.java +++ b/services/core/java/com/android/server/LockSettingsService.java @@ -261,7 +261,9 @@ public class LockSettingsService extends ILockSettings.Stub { showEncryptionNotification(userHandle); } else { UserInfo parent = mUserManager.getProfileParent(user.id); - if (parent != null && mUserManager.isUserUnlocked(parent.getUserHandle())) { + if (parent != null && + mUserManager.isUserUnlocked(parent.getUserHandle()) && + !mUserManager.isQuietModeEnabled(userHandle)) { // Only show notifications for managed profiles once their parent // user is unlocked. showEncryptionNotificationForProfile(userHandle); @@ -348,7 +350,8 @@ public class LockSettingsService extends ILockSettings.Stub { UserInfo profile = profiles.get(i); if (profile.isManagedProfile()) { UserHandle userHandle = profile.getUserHandle(); - if (!mUserManager.isUserUnlocked(userHandle)) { + if (!mUserManager.isUserUnlocked(userHandle) && + !mUserManager.isQuietModeEnabled(userHandle)) { showEncryptionNotificationForProfile(userHandle); } } @@ -702,6 +705,12 @@ public class LockSettingsService extends ILockSettings.Stub { } }; + // Check if the user is currently in quiet mode and start it otherwise + if (mUserManager.isQuietModeEnabled(new UserHandle(userId)) + && mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) { + mUserManager.setQuietModeEnabled(userId, false); + } + try { ActivityManagerNative.getDefault().unlockUser(userId, token, secret, listener); } catch (RemoteException e) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 9703d137a73c..40430b4b3f3e 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1471,6 +1471,7 @@ public final class ActivityManagerService extends ActivityManagerNative static final int NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG = 66; static final int NOTIFY_FORCED_RESIZABLE_MSG = 67; static final int NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG = 68; + static final int VR_MODE_APPLY_IF_NEEDED_MSG = 69; static final int FIRST_ACTIVITY_STACK_MSG = 100; static final int FIRST_BROADCAST_QUEUE_MSG = 200; @@ -2241,6 +2242,17 @@ public final class ActivityManagerService extends ActivityManagerNative } vrService.setVrMode(vrMode, requestedPackage, userId, callingPackage); } break; + case VR_MODE_APPLY_IF_NEEDED_MSG: { + final ActivityRecord r = (ActivityRecord) msg.obj; + final boolean needsVrMode = r != null && r.requestedVrComponent != null; + if (needsVrMode) { + VrManagerInternal vrService = + LocalServices.getService(VrManagerInternal.class); + boolean enable = msg.arg1 == 1; + vrService.setVrMode(enable, r.requestedVrComponent, r.userId, + r.info.getComponentName()); + } + } break; } } }; @@ -3021,6 +3033,11 @@ public final class ActivityManagerService extends ActivityManagerNative mHandler.obtainMessage(VR_MODE_CHANGE_MSG, 0, 0, r)); } + private void applyVrModeIfNeededLocked(ActivityRecord r, boolean enable) { + mHandler.sendMessage( + mHandler.obtainMessage(VR_MODE_APPLY_IF_NEEDED_MSG, enable ? 1 : 0, 0, r)); + } + final void showAskCompatModeDialogLocked(ActivityRecord r) { Message msg = Message.obtain(); msg.what = SHOW_COMPAT_MODE_DIALOG_UI_MSG; @@ -6537,6 +6554,7 @@ public final class ActivityManagerService extends ActivityManagerNative // Some stack visibility might change (e.g. docked stack) mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); + applyVrModeIfNeededLocked(mFocusedActivity, true); } } } finally { @@ -9873,7 +9891,6 @@ public final class ActivityManagerService extends ActivityManagerNative boolean isSystemInitiated = callingUid == Process.SYSTEM_UID; long ident = Binder.clearCallingIdentity(); try { - final ActivityStack stack = mStackSupervisor.getFocusedStack(); if (!isSystemInitiated) { task.mLockTaskUid = callingUid; if (task.mLockTaskAuth == LOCK_TASK_AUTH_PINNABLE) { @@ -9882,11 +9899,12 @@ public final class ActivityManagerService extends ActivityManagerNative StatusBarManagerInternal statusBarManager = LocalServices.getService(StatusBarManagerInternal.class); if (statusBarManager != null) { - statusBarManager.showScreenPinningRequest(); + statusBarManager.showScreenPinningRequest(task.taskId); } return; } + final ActivityStack stack = mStackSupervisor.getFocusedStack(); if (stack == null || task != stack.topTask()) { throw new IllegalArgumentException("Invalid task, not in foreground"); } @@ -9927,15 +9945,13 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override - public void startLockTaskModeOnCurrent() throws RemoteException { - enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "startLockTaskModeOnCurrent"); + public void startSystemLockTaskMode(int taskId) throws RemoteException { + enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "startSystemLockTaskMode"); + // This makes inner call to look as if it was initiated by system. long ident = Binder.clearCallingIdentity(); try { synchronized (this) { - ActivityRecord r = mStackSupervisor.topRunningActivityLocked(); - if (r != null) { - startLockTaskModeLocked(r.task); - } + startLockTaskMode(taskId); } } finally { Binder.restoreCallingIdentity(ident); @@ -9979,8 +9995,9 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override - public void stopLockTaskModeOnCurrent() throws RemoteException { - enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "stopLockTaskModeOnCurrent"); + public void stopSystemLockTaskMode() throws RemoteException { + enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "stopSystemLockTaskMode"); + // This makes inner call to look as if it was initiated by system. long ident = Binder.clearCallingIdentity(); try { stopLockTaskMode(); @@ -20926,6 +20943,7 @@ public final class ActivityManagerService extends ActivityManagerNative SleepTokenImpl token = new SleepTokenImpl(tag); mSleepTokens.add(token); updateSleepIfNeededLocked(); + applyVrModeIfNeededLocked(mFocusedActivity, false); return token; } } diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java index 43e1bdfb5e97..0331470a7f83 100644 --- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java @@ -98,13 +98,16 @@ class ActivityMetricsLogger { * launch * @param componentName the component name of the activity being launched * @param processRunning whether the process that will contains the activity is already running + * @param processSwitch whether the process that will contain the activity didn't have any + * activity that was stopped, i.e. the started activity is "switching" + * processes */ void notifyActivityLaunched(int resultCode, @Nullable String componentName, - boolean processRunning) { + boolean processRunning, boolean processSwitch) { - if (resultCode < 0 || componentName == null) { + if (resultCode < 0 || componentName == null || !processSwitch) { - // Failed to launch, don't track anything. + // Failed to launch or it was not a process switch, so we don't care about the timing. reset(); return; } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index ab3a0b3c1e40..cd465d6827ef 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -2270,7 +2270,7 @@ public final class ActivityStackSupervisor implements DisplayListener { final ActivityRecord r = task.getTopActivity(); final ActivityStack prevStack = task.stack; final boolean wasFocused = isFocusedStack(prevStack) && (topRunningActivityLocked() == r); - final boolean wasResumed = wasFocused && (prevStack.mResumedActivity == r); + final boolean wasResumed = prevStack.mResumedActivity == r; // In some cases the focused stack isn't the front stack. E.g. pinned stack. // Whenever we are moving the top activity from the front stack we want to make sure to move // the stack to the front. diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index 6fba8c85a4f1..a96f23a4cc1b 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -137,6 +137,7 @@ class ActivityStarter { // Share state variable among methods when starting an activity. private ActivityRecord mStartActivity; + private ActivityRecord mReusedActivity; private Intent mIntent; private int mCallingUid; private ActivityOptions mOptions; @@ -785,15 +786,40 @@ class ActivityStarter { final String componentName = outRecord[0] != null ? outRecord[0].shortComponentName : null; - final boolean processRunning = outRecord[0] != null && - mService.mProcessNames.get(outRecord[0].processName, - outRecord[0].appInfo.uid) != null; + final ActivityRecord launchedActivity = mReusedActivity != null + ? mReusedActivity : outRecord[0]; + final ProcessRecord processRecord = launchedActivity != null + ? mService.mProcessNames.get(launchedActivity.processName, + launchedActivity.appInfo.uid) + : null; + final boolean processRunning = processRecord != null; + + // We consider this a "process switch" if the process of the activity that gets launched + // didn't have an activity that was in started state. In this case, we assume that lot + // of caches might be purged so the time until it produces the first frame is very + // interesting. + final boolean processSwitch = processRecord == null + || !hasStartedActivity(processRecord, launchedActivity); mSupervisor.mActivityMetricsLogger.notifyActivityLaunched(res, componentName, - processRunning); + processRunning, processSwitch); return res; } } + final boolean hasStartedActivity(ProcessRecord record, ActivityRecord launchedActivity) { + final ArrayList<ActivityRecord> activities = record.activities; + for (int i = activities.size() - 1; i >= 0; i--) { + final ActivityRecord activity = activities.get(i); + if (launchedActivity == activity) { + continue; + } + if (!activity.stopped) { + return true; + } + } + return false; + } + final int startActivities(IApplicationThread caller, int callingUid, String callingPackage, Intent[] intents, String[] resolvedTypes, IBinder resultTo, Bundle bOptions, int userId) { @@ -883,16 +909,16 @@ class ActivityStarter { mIntent.setFlags(mLaunchFlags); - ActivityRecord intentActivity = getReusableIntentActivity(); + mReusedActivity = getReusableIntentActivity(); final int preferredLaunchStackId = (mOptions != null) ? mOptions.getLaunchStackId() : INVALID_STACK_ID; - if (intentActivity != null) { + if (mReusedActivity != null) { // When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused but // still needs to be a lock task mode violation since the task gets cleared out and // the device would otherwise leave the locked task. - if (mSupervisor.isLockTaskModeViolation(intentActivity.task, + if (mSupervisor.isLockTaskModeViolation(mReusedActivity.task, (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) { mSupervisor.showLockTaskToast(); @@ -901,12 +927,12 @@ class ActivityStarter { } if (mStartActivity.task == null) { - mStartActivity.task = intentActivity.task; + mStartActivity.task = mReusedActivity.task; } - if (intentActivity.task.intent == null) { + if (mReusedActivity.task.intent == null) { // This task was started because of movement of the activity based on affinity... // Now that we are actually launching it, we can assign the base intent. - intentActivity.task.setIntent(mStartActivity); + mReusedActivity.task.setIntent(mStartActivity); } // This code path leads to delivering a new intent, we want to make sure we schedule it @@ -917,7 +943,7 @@ class ActivityStarter { // In this situation we want to remove all activities from the task up to the one // being started. In most cases this means we are resetting the task to its initial // state. - final ActivityRecord top = intentActivity.task.performClearTaskForReuseLocked( + final ActivityRecord top = mReusedActivity.task.performClearTaskForReuseLocked( mStartActivity, mLaunchFlags); if (top != null) { if (top.frontOfTask) { @@ -931,7 +957,7 @@ class ActivityStarter { } } - intentActivity = setTargetStackAndMoveToFrontIfNeeded(intentActivity); + mReusedActivity = setTargetStackAndMoveToFrontIfNeeded(mReusedActivity); if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) { // We don't need to start a new activity, and the client said not to do anything @@ -941,7 +967,7 @@ class ActivityStarter { return START_RETURN_INTENT_TO_CALLER; } - setTaskFromIntentActivity(intentActivity); + setTaskFromIntentActivity(mReusedActivity); if (!mAddingToTask && mReuseTask == null) { // We didn't do anything... but it was needed (a.k.a., client don't use that diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index e69c6621c661..08d23999471f 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -1501,22 +1501,22 @@ final class TaskRecord { Math.min((int)(mTmpStableBounds.width() / density), serviceConfig.screenWidthDp); config.screenHeightDp = Math.min((int)(mTmpStableBounds.height() / density), serviceConfig.screenHeightDp); - config.smallestScreenWidthDp = Math.min(config.screenWidthDp, config.screenHeightDp); // TODO: Orientation? config.orientation = (config.screenWidthDp <= config.screenHeightDp) ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE; - // For calculating screen layout, we need to use the non-decor inset screen area for the - // calculation for compatibility reasons, i.e. screen area without system bars that could - // never go away in Honeycomb. + // For calculating screen layout and smallest screen width, we need to use the non-decor + // inset screen area for the calculation for compatibility reasons, i.e. screen area without + // system bars that could never go away in Honeycomb. final int compatScreenWidthDp = (int)(mTmpNonDecorBounds.width() / density); final int compatScreenHeightDp = (int)(mTmpNonDecorBounds.height() / density); final int sl = Configuration.resetScreenLayout(serviceConfig.screenLayout); final int longSize = Math.max(compatScreenHeightDp, compatScreenWidthDp); - final int shortSize = Math.min(compatScreenHeightDp, compatScreenWidthDp); - config.screenLayout = Configuration.reduceScreenLayout(sl, longSize, shortSize); + config.smallestScreenWidthDp = Math.min(compatScreenHeightDp, compatScreenWidthDp); + config.screenLayout = Configuration.reduceScreenLayout(sl, longSize, + config.smallestScreenWidthDp); return config; } diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 5ebb9a7553ad..4292fcf406b0 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -895,7 +895,10 @@ final class UserController { synchronized (mService) { // Bail if already running unlocked, or if not running at all final UserState uss = mStartedUsers.get(userId); - if (uss == null) return false; + if (uss == null) { + progress.finish(); + return false; + } switch (uss.state) { case STATE_RUNNING_UNLOCKING: case STATE_RUNNING_UNLOCKED: diff --git a/services/core/java/com/android/server/connectivity/DnsEventListenerService.java b/services/core/java/com/android/server/connectivity/DnsEventListenerService.java new file mode 100644 index 000000000000..d3f8af045395 --- /dev/null +++ b/services/core/java/com/android/server/connectivity/DnsEventListenerService.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2016 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.connectivity; + +import android.content.Context; +import android.net.metrics.DnsEvent; +import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; +import android.net.Network; +import android.net.NetworkRequest; +import android.net.metrics.IDnsEventListener; +import android.util.Log; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.IndentingPrintWriter; + +import java.io.PrintWriter; +import java.util.Arrays; +import java.util.SortedMap; +import java.util.TreeMap; + + +/** + * Implementation of the IDnsEventListener interface. + */ +public class DnsEventListenerService extends IDnsEventListener.Stub { + + public static final String SERVICE_NAME = "dns_listener"; + + private static final String TAG = DnsEventListenerService.class.getSimpleName(); + private static final boolean DBG = true; + private static final boolean VDBG = false; + + private static final int MAX_LOOKUPS_PER_DNS_EVENT = 100; + + // Stores the results of a number of consecutive DNS lookups on the same network. + // This class is not thread-safe and it is the responsibility of the service to call its methods + // on one thread at a time. + private static class DnsEventBatch { + private final int mNetId; + + private final byte[] mEventTypes = new byte[MAX_LOOKUPS_PER_DNS_EVENT]; + private final byte[] mReturnCodes = new byte[MAX_LOOKUPS_PER_DNS_EVENT]; + private final int[] mLatenciesMs = new int[MAX_LOOKUPS_PER_DNS_EVENT]; + private int mEventCount; + + public DnsEventBatch(int netId) { + mNetId = netId; + } + + public void addResult(byte eventType, byte returnCode, int latencyMs) { + mEventTypes[mEventCount] = eventType; + mReturnCodes[mEventCount] = returnCode; + mLatenciesMs[mEventCount] = latencyMs; + mEventCount++; + if (mEventCount == MAX_LOOKUPS_PER_DNS_EVENT) { + logAndClear(); + } + } + + public void logAndClear() { + // Did we lose a race with addResult? + if (mEventCount == 0) { + return; + } + + byte[] returnCodes = Arrays.copyOf(mReturnCodes, mEventCount); + int[] latenciesMs = Arrays.copyOf(mLatenciesMs, mEventCount); + DnsEvent.logEvent(mNetId, mEventTypes, mReturnCodes, mLatenciesMs); + maybeLog(String.format("Logging %d results for netId %d", mEventCount, mNetId)); + mEventCount = 0; + } + + // For debugging and unit tests only. + public String toString() { + return String.format("%s %d %d", getClass().getSimpleName(), mNetId, mEventCount); + } + } + + // Only sorted for ease of debugging. Because we only typically have a handful of networks up + // at any given time, performance is not a concern. + @GuardedBy("this") + private SortedMap<Integer, DnsEventBatch> mEventBatches = new TreeMap<>(); + + // We register a NetworkCallback to ensure that when a network disconnects, we flush the DNS + // queries we've logged on that network. Because we do not do this periodically, we might lose + // up to MAX_LOOKUPS_PER_DNS_EVENT lookup stats on each network when the system is shutting + // down. We believe this to be sufficient for now. + private final ConnectivityManager mCm; + private final NetworkCallback mNetworkCallback = new NetworkCallback() { + @Override + public void onLost(Network network) { + synchronized (DnsEventListenerService.this) { + DnsEventBatch batch = mEventBatches.remove(network.netId); + if (batch != null) { + batch.logAndClear(); + } + } + } + }; + + public DnsEventListenerService(Context context) { + // We are started when boot is complete, so ConnectivityService should already be running. + final NetworkRequest request = new NetworkRequest.Builder() + .clearCapabilities() + .build(); + mCm = context.getSystemService(ConnectivityManager.class); + mCm.registerNetworkCallback(request, mNetworkCallback); + } + + @Override + // Called concurrently by multiple binder threads. + public synchronized void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs) { + maybeVerboseLog(String.format("onDnsEvent(%d, %d, %d, %d)", + netId, eventType, returnCode, latencyMs)); + + DnsEventBatch batch = mEventBatches.get(netId); + if (batch == null) { + batch = new DnsEventBatch(netId); + mEventBatches.put(netId, batch); + } + batch.addResult((byte) eventType, (byte) returnCode, latencyMs); + } + + public synchronized void dump(PrintWriter writer) { + IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); + pw.println(TAG + ":"); + pw.increaseIndent(); + for (DnsEventBatch batch : mEventBatches.values()) { + pw.println(batch.toString()); + } + pw.decreaseIndent(); + } + + private static void maybeLog(String s) { + if (DBG) Log.d(TAG, s); + } + + private static void maybeVerboseLog(String s) { + if (VDBG) Log.d(TAG, s); + } +} diff --git a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java index f91db7813d42..ac5c4ae982d5 100644 --- a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java +++ b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java @@ -55,6 +55,8 @@ public class MetricsLoggerService extends SystemService { if (DBG) Log.d(TAG, "onBootPhase: PHASE_SYSTEM_SERVICES_READY"); publishBinderService(ConnectivityMetricsLogger.CONNECTIVITY_METRICS_LOGGER_SERVICE, mBinder); + mDnsListener = new DnsEventListenerService(getContext()); + publishBinderService(mDnsListener.SERVICE_NAME, mDnsListener); } } @@ -89,6 +91,8 @@ public class MetricsLoggerService extends SystemService { private final ArrayDeque<ConnectivityMetricsEvent> mEvents = new ArrayDeque<>(); + private DnsEventListenerService mDnsListener; + private void enforceConnectivityInternalPermission() { getContext().enforceCallingOrSelfPermission( android.Manifest.permission.CONNECTIVITY_INTERNAL, @@ -159,10 +163,12 @@ public class MetricsLoggerService extends SystemService { synchronized (mEvents) { pw.println("Number of events: " + mEvents.size()); - pw.println("Time span: " + - DateUtils.formatElapsedTime( - (System.currentTimeMillis() - mEvents.peekFirst().timestamp) - / 1000)); + if (mEvents.size() > 0) { + pw.println("Time span: " + + DateUtils.formatElapsedTime( + (System.currentTimeMillis() - mEvents.peekFirst().timestamp) + / 1000)); + } if (dumpSerializedSize) { long dataSize = 0; @@ -193,6 +199,9 @@ public class MetricsLoggerService extends SystemService { pw.println(pi.toString()); } } + + pw.println(); + mDnsListener.dump(pw); } public long logEvent(ConnectivityMetricsEvent event) { @@ -291,14 +300,14 @@ public class MetricsLoggerService extends SystemService { */ public ConnectivityMetricsEvent[] getEvents(ConnectivityMetricsEvent.Reference reference) { enforceDumpPermission(); - long ref = reference.value; + long ref = reference.getValue(); if (VDBG) Log.v(TAG, "getEvents(" + ref + ")"); ConnectivityMetricsEvent[] result; synchronized (mEvents) { if (ref > mLastEventReference) { Log.e(TAG, "Invalid reference"); - reference.value = mLastEventReference; + reference.setValue(mLastEventReference); return null; } if (ref < mLastEventReference - mEvents.size()) { @@ -320,7 +329,7 @@ public class MetricsLoggerService extends SystemService { } } - reference.value = mLastEventReference; + reference.setValue(mLastEventReference); return result; } diff --git a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java new file mode 100644 index 000000000000..d2f015fad881 --- /dev/null +++ b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java @@ -0,0 +1,156 @@ +/** + * Copyright (C) 2016 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.fingerprint; + +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.MetricsProto.MetricsEvent; + +import android.content.Context; +import android.hardware.fingerprint.Fingerprint; +import android.hardware.fingerprint.FingerprintManager; +import android.hardware.fingerprint.IFingerprintDaemon; +import android.hardware.fingerprint.IFingerprintServiceReceiver; +import android.os.IBinder; +import android.os.RemoteException; +import android.system.ErrnoException; +import android.util.Slog; + +/** + * A class to keep track of the authentication state for a given client. + */ +public abstract class AuthenticationClient extends ClientMonitor { + private long mOpId; + + public abstract boolean handleFailedAttempt(); + public abstract void resetFailedAttempts(); + + public AuthenticationClient(Context context, long halDeviceId, IBinder token, + IFingerprintServiceReceiver receiver, int userId, int groupId, long opId, + boolean restricted, String owner) { + super(context, halDeviceId, token, receiver, userId, groupId, restricted, owner); + mOpId = opId; + } + + @Override + public boolean onAuthenticated(int fingerId, int groupId) { + boolean result = false; + boolean authenticated = fingerId != 0; + + IFingerprintServiceReceiver receiver = getReceiver(); + if (receiver != null) { + try { + MetricsLogger.action(getContext(), MetricsEvent.ACTION_FINGERPRINT_AUTH, + authenticated); + if (!authenticated) { + receiver.onAuthenticationFailed(getHalDeviceId()); + } else { + if (DEBUG) { + Slog.v(TAG, "onAuthenticated(owner=" + getOwnerString() + + ", id=" + fingerId + ", gp=" + groupId + ")"); + } + Fingerprint fp = !getIsRestricted() + ? new Fingerprint("" /* TODO */, groupId, fingerId, getHalDeviceId()) + : null; + receiver.onAuthenticationSucceeded(getHalDeviceId(), fp); + } + } catch (RemoteException e) { + Slog.w(TAG, "Failed to notify Authenticated:", e); + result = true; // client failed + } + } else { + result = true; // client not listening + } + if (fingerId == 0) { + if (receiver != null) { + FingerprintUtils.vibrateFingerprintError(getContext()); + } + // allow system-defined limit of number of attempts before giving up + result |= handleFailedAttempt(); + } else { + if (receiver != null) { + FingerprintUtils.vibrateFingerprintSuccess(getContext()); + } + result |= true; // we have a valid fingerprint, done + resetFailedAttempts(); + } + return result; + } + + /** + * Start authentication + */ + @Override + public int start() { + IFingerprintDaemon daemon = getFingerprintDaemon(); + if (daemon == null) { + Slog.w(TAG, "start authentication: no fingeprintd!"); + return ERROR_ESRCH; + } + try { + final int result = daemon.authenticate(mOpId, getGroupId()); + if (result != 0) { + Slog.w(TAG, "startAuthentication failed, result=" + result); + onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE); + return result; + } + if (DEBUG) Slog.w(TAG, "client " + getOwnerString() + " is authenticating..."); + } catch (RemoteException e) { + Slog.e(TAG, "startAuthentication failed", e); + return ERROR_ESRCH; + } + return 0; // success + } + + @Override + public int stop(boolean initiatedByClient) { + IFingerprintDaemon daemon = getFingerprintDaemon(); + if (daemon == null) { + Slog.w(TAG, "stopAuthentication: no fingeprintd!"); + return ERROR_ESRCH; + } + try { + final int result = daemon.cancelAuthentication(); + if (result != 0) { + Slog.w(TAG, "stopAuthentication failed, result=" + result); + return result; + } + if (DEBUG) Slog.w(TAG, "client " + getOwnerString() + " is no longer authenticating"); + } catch (RemoteException e) { + Slog.e(TAG, "stopAuthentication failed", e); + return ERROR_ESRCH; + } + return 0; // success + } + + @Override + public boolean onEnrollResult(int fingerId, int groupId, int rem) { + if (DEBUG) Slog.w(TAG, "onEnrollResult() called for authenticate!"); + return true; // Invalid for Authenticate + } + + @Override + public boolean onRemoved(int fingerId, int groupId) { + if (DEBUG) Slog.w(TAG, "onRemoved() called for authenticate!"); + return true; // Invalid for Authenticate + } + + @Override + public boolean onEnumerationResult(int fingerId, int groupId) { + if (DEBUG) Slog.w(TAG, "onEnumerationResult() called for authenticate!"); + return true; // Invalid for Authenticate + } +} diff --git a/services/core/java/com/android/server/fingerprint/ClientMonitor.java b/services/core/java/com/android/server/fingerprint/ClientMonitor.java new file mode 100644 index 000000000000..90998edd6d33 --- /dev/null +++ b/services/core/java/com/android/server/fingerprint/ClientMonitor.java @@ -0,0 +1,211 @@ +/** + * Copyright (C) 2016 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.fingerprint; + +import android.Manifest; +import android.content.Context; +import android.hardware.fingerprint.FingerprintManager; +import android.hardware.fingerprint.IFingerprintDaemon; +import android.hardware.fingerprint.IFingerprintServiceReceiver; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Slog; + +import java.util.NoSuchElementException; + +/** + * Abstract base class for keeping track and dispatching events from fingerprintd to the + * the current client. Subclasses are responsible for coordinating the interaction with + * fingerprintd for the specific action (e.g. authenticate, enroll, enumerate, etc.). + */ +public abstract class ClientMonitor implements IBinder.DeathRecipient { + protected static final String TAG = FingerprintService.TAG; // TODO: get specific name + protected static final int ERROR_ESRCH = 3; // Likely fingerprintd is dead. See errno.h. + protected static final boolean DEBUG = FingerprintService.DEBUG; + private IBinder mToken; + private IFingerprintServiceReceiver mReceiver; + private int mUserId; + private int mGroupId; + private boolean mIsRestricted; // True if client does not have MANAGE_FINGERPRINT permission + private String mOwner; + private Context mContext; + private long mHalDeviceId; + + /** + * @param context context of FingerprintService + * @param halDeviceId the HAL device ID of the associated fingerprint hardware + * @param token a unique token for the client + * @param receiver recipient of related events (e.g. authentication) + * @param userId userId for the fingerprint set + * @param groupId groupId for the fingerprint set + * @param restricted whether or not client has the {@link Manifest#MANAGE_FINGERPRINT} + * permission + * @param owner name of the client that owns this + */ + public ClientMonitor(Context context, long halDeviceId, IBinder token, + IFingerprintServiceReceiver receiver, int userId, int groupId,boolean restricted, + String owner) { + mContext = context; + mHalDeviceId = halDeviceId; + mToken = token; + mReceiver = receiver; + mUserId = userId; + mGroupId = groupId; + mIsRestricted = restricted; + mOwner = owner; + try { + token.linkToDeath(this, 0); + } catch (RemoteException e) { + Slog.w(TAG, "caught remote exception in linkToDeath: ", e); + } + } + + /** + * Contacts fingerprintd to start the client. + * @return 0 on succes, errno from driver on failure + */ + public abstract int start(); + + /** + * Contacts fingerprintd to stop the client. + * @param initiatedByClient whether the operation is at the request of a client + */ + public abstract int stop(boolean initiatedByClient); + + /** + * Method to explicitly poke powermanager on events + */ + public abstract void notifyUserActivity(); + + /** + * Gets the fingerprint daemon from the cached state in the container class. + */ + public abstract IFingerprintDaemon getFingerprintDaemon(); + + // Event callbacks from driver. Inappropriate calls is flagged/logged by the + // respective client (e.g. enrolling shouldn't get authenticate events). + // All of these return 'true' if the operation is completed and it's ok to move + // to the next client (e.g. authentication accepts or rejects a fingerprint). + public abstract boolean onEnrollResult(int fingerId, int groupId, int rem); + public abstract boolean onAuthenticated(int fingerId, int groupId); + public abstract boolean onRemoved(int fingerId, int groupId); + public abstract boolean onEnumerationResult(int fingerId, int groupId); + + /** + * Called when we get notification from fingerprintd that an image has been acquired. + * Common to authenticate and enroll. + * @param acquiredInfo info about the current image acquisition + * @return true if client should be removed + */ + public boolean onAcquired(int acquiredInfo) { + if (mReceiver == null) + return true; // client not connected + try { + mReceiver.onAcquired(getHalDeviceId(), acquiredInfo); + return false; // acquisition continues... + } catch (RemoteException e) { + Slog.w(TAG, "Failed to invoke sendAcquired:", e); + return true; // client failed + } finally { + // Good scans will keep the device awake + if (acquiredInfo == FingerprintManager.FINGERPRINT_ACQUIRED_GOOD) { + notifyUserActivity(); + } + } + } + + /** + * Called when we get notification from fingerprintd that an error has occurred with the + * current operation. Common to authenticate, enroll, enumerate and remove. + * @param error + * @return true if client should be removed + */ + public boolean onError(int error) { + if (mReceiver != null) { + try { + mReceiver.onError(getHalDeviceId(), error); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to invoke sendError:", e); + } + } + return true; // errors always remove current client + } + + public void destroy() { + if (mToken != null) { + try { + mToken.unlinkToDeath(this, 0); + } catch (NoSuchElementException e) { + // TODO: remove when duplicate call bug is found + Slog.e(TAG, "destroy(): " + this + ":", new Exception("here")); + } + mToken = null; + } + mReceiver = null; + } + + @Override + public void binderDied() { + mToken = null; + mReceiver = null; + onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE); + } + + @Override + protected void finalize() throws Throwable { + try { + if (mToken != null) { + if (DEBUG) Slog.w(TAG, "removing leaked reference: " + mToken); + onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE); + } + } finally { + super.finalize(); + } + } + + public final Context getContext() { + return mContext; + } + + public final long getHalDeviceId() { + return mHalDeviceId; + } + + public final String getOwnerString() { + return mOwner; + } + + public final IFingerprintServiceReceiver getReceiver() { + return mReceiver; + } + + public final boolean getIsRestricted() { + return mIsRestricted; + } + + public final int getUserId() { + return mUserId; + } + + public final int getGroupId() { + return mGroupId; + } + + public final IBinder getToken() { + return mToken; + } +} diff --git a/services/core/java/com/android/server/fingerprint/EnrollClient.java b/services/core/java/com/android/server/fingerprint/EnrollClient.java new file mode 100644 index 000000000000..ce5b89080fb4 --- /dev/null +++ b/services/core/java/com/android/server/fingerprint/EnrollClient.java @@ -0,0 +1,136 @@ +/** + * Copyright (C) 2016 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.fingerprint; + +import android.content.Context; +import android.hardware.fingerprint.FingerprintManager; +import android.hardware.fingerprint.IFingerprintDaemon; +import android.hardware.fingerprint.IFingerprintServiceReceiver; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Slog; + +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.MetricsProto.MetricsEvent; + +import java.util.Arrays; + +/** + * A class to keep track of the enrollment state for a given client. + */ +public abstract class EnrollClient extends ClientMonitor { + private static final long MS_PER_SEC = 1000; + private static final int ENROLLMENT_TIMEOUT_MS = 60 * 1000; // 1 minute + private byte[] mCryptoToken; + + public EnrollClient(Context context, long halDeviceId, IBinder token, + IFingerprintServiceReceiver receiver, int userId, int groupId, byte [] cryptoToken, + boolean restricted, String owner) { + super(context, halDeviceId, token, receiver, userId, groupId, restricted, owner); + mCryptoToken = Arrays.copyOf(cryptoToken, cryptoToken.length); + } + + @Override + public boolean onEnrollResult(int fingerId, int groupId, int remaining) { + if (remaining == 0) { + FingerprintUtils.getInstance().addFingerprintForUser(getContext(), fingerId, + getUserId()); + } + return sendEnrollResult(fingerId, groupId, remaining); + } + + /* + * @return true if we're done. + */ + private boolean sendEnrollResult(int fpId, int groupId, int remaining) { + IFingerprintServiceReceiver receiver = getReceiver(); + if (receiver == null) + return true; // client not listening + + FingerprintUtils.vibrateFingerprintSuccess(getContext()); + MetricsLogger.action(getContext(), MetricsEvent.ACTION_FINGERPRINT_ENROLL); + try { + receiver.onEnrollResult(getHalDeviceId(), fpId, groupId, remaining); + return remaining == 0; + } catch (RemoteException e) { + Slog.w(TAG, "Failed to notify EnrollResult:", e); + return true; + } + } + + @Override + public int start() { + IFingerprintDaemon daemon = getFingerprintDaemon(); + if (daemon == null) { + Slog.w(TAG, "enroll: no fingeprintd!"); + return ERROR_ESRCH; + } + final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC); + try { + final int result = daemon.enroll(mCryptoToken, getGroupId(), timeout); + if (result != 0) { + Slog.w(TAG, "startEnroll failed, result=" + result); + onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE); + return result; + } + } catch (RemoteException e) { + Slog.e(TAG, "startEnroll failed", e); + } + return 0; // success + } + + @Override + public int stop(boolean initiatedByClient) { + IFingerprintDaemon daemon = getFingerprintDaemon(); + if (daemon == null) { + Slog.w(TAG, "stopEnrollment: no fingeprintd!"); + return ERROR_ESRCH; + } + try { + final int result = daemon.cancelEnrollment(); + if (result != 0) { + Slog.w(TAG, "startEnrollCancel failed, result = " + result); + return result; + } + } catch (RemoteException e) { + Slog.e(TAG, "stopEnrollment failed", e); + } + if (initiatedByClient) { + onError(FingerprintManager.FINGERPRINT_ERROR_CANCELED); + } + return 0; + } + + @Override + public boolean onRemoved(int fingerId, int groupId) { + if (DEBUG) Slog.w(TAG, "onRemoved() called for enroll!"); + return true; // Invalid for EnrollClient + } + + @Override + public boolean onEnumerationResult(int fingerId, int groupId) { + if (DEBUG) Slog.w(TAG, "onEnumerationResult() called for enroll!"); + return true; // Invalid for EnrollClient + } + + @Override + public boolean onAuthenticated(int fingerId, int groupId) { + if (DEBUG) Slog.w(TAG, "onAuthenticated() called for enroll!"); + return true; // Invalid for EnrollClient + } + +} diff --git a/services/core/java/com/android/server/fingerprint/EnumerateClient.java b/services/core/java/com/android/server/fingerprint/EnumerateClient.java new file mode 100644 index 000000000000..b2e4099451ca --- /dev/null +++ b/services/core/java/com/android/server/fingerprint/EnumerateClient.java @@ -0,0 +1,92 @@ +/** + * Copyright (C) 2016 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.fingerprint; + +import android.content.Context; +import android.hardware.fingerprint.FingerprintManager; +import android.hardware.fingerprint.IFingerprintDaemon; +import android.hardware.fingerprint.IFingerprintServiceReceiver; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Slog; + +/** + * A class to keep track of the enumeration state for a given client. + */ +public abstract class EnumerateClient extends ClientMonitor { + public EnumerateClient(Context context, long halDeviceId, IBinder token, + IFingerprintServiceReceiver receiver, int userId, int groupId, + boolean restricted, String owner) { + super(context, halDeviceId, token, receiver, userId, groupId, restricted, owner); + } + + @Override + public int start() { + IFingerprintDaemon daemon = getFingerprintDaemon(); + // The fingerprint template ids will be removed when we get confirmation from the HAL + try { + final int result = daemon.enumerate(); + if (result != 0) { + Slog.w(TAG, "start enumerate for user " + getUserId() + + " failed, result=" + result); + onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE); + return result; + } + } catch (RemoteException e) { + Slog.e(TAG, "startRemove failed", e); + } + return 0; + } + + @Override + public int stop(boolean initiatedByClient) { + IFingerprintDaemon daemon = getFingerprintDaemon(); + if (daemon == null) { + Slog.w(TAG, "stopAuthentication: no fingeprintd!"); + return ERROR_ESRCH; + } + try { + final int result = daemon.cancelEnumeration(); + if (result != 0) { + Slog.w(TAG, "stop enumeration failed, result=" + result); + return result; + } + } catch (RemoteException e) { + Slog.e(TAG, "stop enumeration failed", e); + return ERROR_ESRCH; + } + // We don't actually stop enumerate, but inform the client that the cancel operation + // succeeded so we can start the next operation. + if (initiatedByClient) { + onError(FingerprintManager.FINGERPRINT_ERROR_CANCELED); + } + return 0; // success + } + + @Override + public boolean onEnumerationResult(int fingerId, int groupId) { + IFingerprintServiceReceiver receiver = getReceiver(); + if (receiver == null) + return true; // client not listening + try { + receiver.onRemoved(getHalDeviceId(), fingerId, groupId); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to notify enumerated:", e); + } + return fingerId == 0; // done when id hits 0 + } +} diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java index e3f3849c79d3..2dafa3e8a1c0 100644 --- a/services/core/java/com/android/server/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java @@ -19,7 +19,6 @@ package com.android.server.fingerprint; import android.Manifest; import android.app.ActivityManager; import android.app.ActivityManager.RunningAppProcessInfo; -import android.app.trust.TrustManager; import android.app.ActivityManagerNative; import android.app.AlarmManager; import android.app.AppOpsManager; @@ -48,7 +47,6 @@ import android.os.UserManager; import android.util.Slog; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.MetricsProto.MetricsEvent; import com.android.server.SystemService; import org.json.JSONArray; @@ -75,7 +73,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.NoSuchElementException; /** * A service to manage multiple clients that want to access the fingerprint HAL API. @@ -85,31 +82,36 @@ import java.util.NoSuchElementException; * @hide */ public class FingerprintService extends SystemService implements IBinder.DeathRecipient { - private static final String TAG = "FingerprintService"; - private static final boolean DEBUG = true; + static final String TAG = "FingerprintService"; + static final boolean DEBUG = true; private static final String FP_DATA_DIR = "fpdata"; private static final String FINGERPRINTD = "android.hardware.fingerprint.IFingerprintDaemon"; private static final int MSG_USER_SWITCHING = 10; - private static final int ENROLLMENT_TIMEOUT_MS = 60 * 1000; // 1 minute private static final String ACTION_LOCKOUT_RESET = "com.android.server.fingerprint.ACTION_LOCKOUT_RESET"; - private ClientMonitor mAuthClient = null; - private ClientMonitor mEnrollClient = null; - private ClientMonitor mRemoveClient = null; private final ArrayList<FingerprintServiceLockoutResetMonitor> mLockoutMonitors = new ArrayList<>(); private final AppOpsManager mAppOps; - private static final long MS_PER_SEC = 1000; private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30*1000; private static final int MAX_FAILED_ATTEMPTS = 5; - private static final int FINGERPRINT_ACQUIRED_GOOD = 0; + private static final long CANCEL_TIMEOUT_LIMIT = 300; // max wait for onCancel() from HAL,in ms private final String mKeyguardPackage; private int mCurrentUserId = UserHandle.USER_CURRENT; - private int mUserIdForRemove = UserHandle.USER_NULL; + private final FingerprintUtils mFingerprintUtils = FingerprintUtils.getInstance(); + private Context mContext; + private long mHalDeviceId; + private int mFailedAttempts; + private IFingerprintDaemon mDaemon; + private final PowerManager mPowerManager; + private final AlarmManager mAlarmManager; + private final UserManager mUserManager; + private ClientMonitor mCurrentClient; + private ClientMonitor mPendingClient; + private long mCurrentAuthenticatorId; - Handler mHandler = new Handler() { + private Handler mHandler = new Handler() { @Override public void handleMessage(android.os.Message msg) { switch (msg.what) { @@ -123,15 +125,6 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe } }; - private final FingerprintUtils mFingerprintUtils = FingerprintUtils.getInstance(); - private Context mContext; - private long mHalDeviceId; - private int mFailedAttempts; - private IFingerprintDaemon mDaemon; - private final PowerManager mPowerManager; - private final AlarmManager mAlarmManager; - private final UserManager mUserManager; - private final BroadcastReceiver mLockoutReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -148,6 +141,26 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe } }; + private final Runnable mResetClientState = new Runnable() { + @Override + public void run() { + // Warning: if we get here, the driver never confirmed our call to cancel the current + // operation (authenticate, enroll, remove, enumerate, etc), which is + // really bad. The result will be a 3-second delay in starting each new client. + // If you see this on a device, make certain the driver notifies with + // {@link FingerprintManager#FINGERPRINT_ERROR_CANCEL} in response to cancel() + // once it has successfully switched to the IDLE state in the fingerprint HAL. + // Additionally,{@link FingerprintManager#FINGERPRINT_ERROR_CANCEL} should only be sent + // in response to an actual cancel() call. + Slog.w(TAG, "Client " + + (mCurrentClient != null ? mCurrentClient.getOwnerString() : "null") + + " failed to respond to cancel, starting client " + + (mPendingClient != null ? mPendingClient.getOwnerString() : "null")); + mCurrentClient = null; + startClient(mPendingClient, false); + } + }; + public FingerprintService(Context context) { super(context); mContext = context; @@ -203,64 +216,49 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe // TODO: update fingerprint/name pairs } - protected void handleRemoved(long deviceId, int fingerId, int groupId) { - final ClientMonitor client = mRemoveClient; - if (fingerId != 0) { - removeTemplateForUser(mUserIdForRemove, fingerId); - } else { - mUserIdForRemove = UserHandle.USER_NULL; - } - if (client != null && client.sendRemoved(fingerId, groupId)) { + protected void handleError(long deviceId, int error) { + ClientMonitor client = mCurrentClient; + if (client != null && client.onError(error)) { removeClient(client); } + if (DEBUG) Slog.v(TAG, "handleError(client=" + + client != null ? client.getOwnerString() : "null" + ", error = " + error + ")"); + // This is the magic code that starts the next client when the old client finishes. + if (error == FingerprintManager.FINGERPRINT_ERROR_CANCELED) { + mHandler.removeCallbacks(mResetClientState); + if (mPendingClient != null) { + if (DEBUG) Slog.v(TAG, "start pending client " + mPendingClient.getOwnerString()); + startClient(mPendingClient, false); + mPendingClient = null; + } + } } - protected void handleError(long deviceId, int error) { - if (mEnrollClient != null) { - final IBinder token = mEnrollClient.token; - if (mEnrollClient.sendError(error)) { - stopEnrollment(token, false); - } - } else if (mAuthClient != null) { - final IBinder token = mAuthClient.token; - if (mAuthClient.sendError(error)) { - stopAuthentication(token, false); - } - } else if (mRemoveClient != null) { - if (mRemoveClient.sendError(error)) removeClient(mRemoveClient); + protected void handleRemoved(long deviceId, int fingerId, int groupId) { + ClientMonitor client = mCurrentClient; + if (client != null && client.onRemoved(fingerId, groupId)) { + removeClient(client); } } protected void handleAuthenticated(long deviceId, int fingerId, int groupId) { - if (mAuthClient != null) { - final IBinder token = mAuthClient.token; - if (mAuthClient.sendAuthenticated(fingerId, groupId)) { - stopAuthentication(token, false); - removeClient(mAuthClient); - } + ClientMonitor client = mCurrentClient; + if (client != null && client.onAuthenticated(fingerId, groupId)) { + removeClient(client); } } protected void handleAcquired(long deviceId, int acquiredInfo) { - if (mEnrollClient != null) { - if (mEnrollClient.sendAcquired(acquiredInfo)) { - removeClient(mEnrollClient); - } - } else if (mAuthClient != null) { - if (mAuthClient.sendAcquired(acquiredInfo)) { - removeClient(mAuthClient); - } + ClientMonitor client = mCurrentClient; + if (client != null && client.onAcquired(acquiredInfo)) { + removeClient(client); } } protected void handleEnrollResult(long deviceId, int fingerId, int groupId, int remaining) { - if (mEnrollClient != null) { - if (mEnrollClient.sendEnrollResult(fingerId, groupId, remaining)) { - if (remaining == 0) { - addTemplateForUser(mEnrollClient, fingerId); - removeClient(mEnrollClient); - } - } + ClientMonitor client = mCurrentClient; + if (client != null && client.onEnrollResult(fingerId, groupId, remaining)) { + removeClient(client); } } @@ -274,14 +272,16 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe } private void removeClient(ClientMonitor client) { - if (client == null) return; - client.destroy(); - if (client == mAuthClient) { - mAuthClient = null; - } else if (client == mEnrollClient) { - mEnrollClient = null; - } else if (client == mRemoveClient) { - mRemoveClient = null; + if (client != null) { + client.destroy(); + if (client != mCurrentClient && mCurrentClient != null) { + Slog.w(TAG, "Unexpected client: " + client.getOwnerString() + "expected: " + + mCurrentClient != null ? mCurrentClient.getOwnerString() : "null"); + } + } + if (mCurrentClient != null) { + if (DEBUG) Slog.v(TAG, "Done with client: " + client.getOwnerString()); + mCurrentClient = null; } } @@ -303,60 +303,6 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe new Intent(ACTION_LOCKOUT_RESET), PendingIntent.FLAG_UPDATE_CURRENT); } - private void resetFailedAttempts() { - if (DEBUG && inLockoutMode()) { - Slog.v(TAG, "Reset fingerprint lockout"); - } - mFailedAttempts = 0; - // If we're asked to reset failed attempts externally (i.e. from Keyguard), the alarm might - // still be pending; remove it. - cancelLockoutReset(); - notifyLockoutResetMonitors(); - } - - private boolean handleFailedAttempt(ClientMonitor clientMonitor) { - mFailedAttempts++; - if (inLockoutMode()) { - // Failing multiple times will continue to push out the lockout time. - scheduleLockoutReset(); - if (clientMonitor != null - && !clientMonitor.sendError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) { - Slog.w(TAG, "Cannot send lockout message to client"); - } - return true; - } - return false; - } - - private void removeTemplateForUser(int userId, int fingerId) { - mFingerprintUtils.removeFingerprintIdForUser(mContext, fingerId, userId); - } - - private void addTemplateForUser(ClientMonitor clientMonitor, int fingerId) { - mFingerprintUtils.addFingerprintForUser(mContext, fingerId, clientMonitor.userId); - } - - void startEnrollment(IBinder token, byte[] cryptoToken, int groupId, - IFingerprintServiceReceiver receiver, int flags, boolean restricted) { - IFingerprintDaemon daemon = getFingerprintDaemon(); - if (daemon == null) { - Slog.w(TAG, "enroll: no fingeprintd!"); - return; - } - stopPendingOperations(true); - mEnrollClient = new ClientMonitor(token, receiver, groupId, restricted, token.toString()); - final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC); - try { - final int result = daemon.enroll(cryptoToken, groupId, timeout); - if (result != 0) { - Slog.w(TAG, "startEnroll failed, result=" + result); - handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE); - } - } catch (RemoteException e) { - Slog.e(TAG, "startEnroll failed", e); - } - } - public long startPreEnroll(IBinder token) { IFingerprintDaemon daemon = getFingerprintDaemon(); if (daemon == null) { @@ -385,123 +331,52 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe return 0; } - private void stopPendingOperations(boolean initiatedByClient) { - if (mEnrollClient != null) { - stopEnrollment(mEnrollClient.token, initiatedByClient); - } - if (mAuthClient != null) { - stopAuthentication(mAuthClient.token, initiatedByClient); - } - // mRemoveClient is allowed to continue - } - - /** - * Stop enrollment in progress and inform client if they initiated it. - * - * @param token token for client - * @param initiatedByClient if this call is the result of client action (e.g. calling cancel) - */ - void stopEnrollment(IBinder token, boolean initiatedByClient) { - IFingerprintDaemon daemon = getFingerprintDaemon(); - if (daemon == null) { - Slog.w(TAG, "stopEnrollment: no fingeprintd!"); - return; - } - final ClientMonitor client = mEnrollClient; - if (client == null || client.token != token) return; - if (initiatedByClient) { - try { - int result = daemon.cancelEnrollment(); - if (result != 0) { - Slog.w(TAG, "startEnrollCancel failed, result = " + result); - } - } catch (RemoteException e) { - Slog.e(TAG, "stopEnrollment failed", e); - } - client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED); - } - removeClient(mEnrollClient); - } - - void startAuthentication(IBinder token, long opId, int realUserId, int groupId, - IFingerprintServiceReceiver receiver, int flags, boolean restricted, - String opPackageName) { - IFingerprintDaemon daemon = getFingerprintDaemon(); - if (daemon == null) { - Slog.w(TAG, "startAuthentication: no fingeprintd!"); - return; - } - stopPendingOperations(true); - updateActiveGroup(groupId, opPackageName); - mAuthClient = new ClientMonitor(token, receiver, groupId, restricted, opPackageName); - if (inLockoutMode()) { - Slog.v(TAG, "In lockout mode; disallowing authentication"); - if (!mAuthClient.sendError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) { - Slog.w(TAG, "Cannot send timeout message to client"); - } - mAuthClient = null; - return; - } - try { - final int result = daemon.authenticate(opId, groupId); - if (result != 0) { - Slog.w(TAG, "startAuthentication failed, result=" + result); - handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE); - } - } catch (RemoteException e) { - Slog.e(TAG, "startAuthentication failed", e); - } - } - /** - * Stop authentication in progress and inform client if they initiated it. - * - * @param token token for client - * @param initiatedByClient if this call is the result of client action (e.g. calling cancel) + * Calls fingerprintd to switch states to the new task. If there's already a current task, + * it calls cancel() and sets mPendingClient to begin when the current task finishes + * ({@link FingerprintManager#FINGERPRINT_ERROR_CANCELED}). + * @param newClient the new client that wants to connect + * @param initiatedByClient true for authenticate, remove and enroll */ - void stopAuthentication(IBinder token, boolean initiatedByClient) { - IFingerprintDaemon daemon = getFingerprintDaemon(); - if (daemon == null) { - Slog.w(TAG, "stopAuthentication: no fingeprintd!"); - return; - } - final ClientMonitor client = mAuthClient; - if (client == null || client.token != token) return; - if (initiatedByClient) { - try { - int result = daemon.cancelAuthentication(); - if (result != 0) { - Slog.w(TAG, "stopAuthentication failed, result=" + result); - } - } catch (RemoteException e) { - Slog.e(TAG, "stopAuthentication failed", e); - } - client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED); + private void startClient(ClientMonitor newClient, boolean initiatedByClient) { + ClientMonitor currentClient = mCurrentClient; + if (currentClient != null) { + if (DEBUG) Slog.v(TAG, "request stop current client " + currentClient.getOwnerString()); + currentClient.stop(initiatedByClient); + mPendingClient = newClient; + mHandler.removeCallbacks(mResetClientState); + mHandler.postDelayed(mResetClientState, CANCEL_TIMEOUT_LIMIT); + } else if (newClient != null) { + mCurrentClient = newClient; + if (DEBUG) Slog.v(TAG, "starting client " + + newClient.getClass().getSuperclass().getSimpleName() + + "(" + newClient.getOwnerString() + ")" + + ", initiatedByClient = " + initiatedByClient + ")"); + newClient.start(); } - removeClient(mAuthClient); } - void startRemove(IBinder token, int fingerId, int userId, + void startRemove(IBinder token, int fingerId, int userId, int groupId, IFingerprintServiceReceiver receiver, boolean restricted) { IFingerprintDaemon daemon = getFingerprintDaemon(); if (daemon == null) { Slog.w(TAG, "startRemove: no fingeprintd!"); return; } + RemovalClient client = new RemovalClient(getContext(), mHalDeviceId, token, + receiver, userId, groupId, fingerId, restricted, token.toString()) { + @Override + public void notifyUserActivity() { + FingerprintService.this.userActivity(); + } - stopPendingOperations(true); - mRemoveClient = new ClientMonitor(token, receiver, userId, restricted, token.toString()); - mUserIdForRemove = mCurrentUserId; - // The fingerprint template ids will be removed when we get confirmation from the HAL - try { - final int result = daemon.remove(fingerId, userId); - if (result != 0) { - Slog.w(TAG, "startRemove with id = " + fingerId + " failed, result=" + result); - handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE); + @Override + public IFingerprintDaemon getFingerprintDaemon() { + FingerprintService.this.getFingerprintDaemon(); + return null; } - } catch (RemoteException e) { - Slog.e(TAG, "startRemove failed", e); - } + }; + startClient(client, true); } public List<Fingerprint> getEnrolledFingerprints(int userId) { @@ -572,10 +447,9 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe * @param foregroundOnly only allow this call while app is in the foreground * @return true if caller can use fingerprint API */ - private boolean canUseFingerprint(String opPackageName, boolean foregroundOnly) { + private boolean canUseFingerprint(String opPackageName, boolean foregroundOnly, int uid, + int pid) { checkPermission(USE_FINGERPRINT); - final int uid = Binder.getCallingUid(); - final int pid = Binder.getCallingPid(); if (isKeyguard(opPackageName)) { return true; // Keyguard is always allowed } @@ -620,165 +494,83 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe } } - private class ClientMonitor implements IBinder.DeathRecipient { - IBinder token; - IFingerprintServiceReceiver receiver; - int userId; - boolean restricted; // True if client does not have MANAGE_FINGERPRINT permission - String owner; - - public ClientMonitor(IBinder token, IFingerprintServiceReceiver receiver, int userId, - boolean restricted, String owner) { - this.token = token; - this.receiver = receiver; - this.userId = userId; - this.restricted = restricted; - this.owner = owner; // name of the client that owns this - for debugging - try { - token.linkToDeath(this, 0); - } catch (RemoteException e) { - Slog.w(TAG, "caught remote exception in linkToDeath: ", e); - } - } + private void startAuthentication(IBinder token, long opId, int realUserId, int groupId, + IFingerprintServiceReceiver receiver, int flags, boolean restricted, + String opPackageName) { + updateActiveGroup(groupId, opPackageName); - public void destroy() { - if (token != null) { - try { - token.unlinkToDeath(this, 0); - } catch (NoSuchElementException e) { - // TODO: remove when duplicate call bug is found - Slog.e(TAG, "destroy(): " + this + ":", new Exception("here")); + if (DEBUG) Slog.v(TAG, "startAuthentication(" + opPackageName + ")"); + + AuthenticationClient client = new AuthenticationClient(getContext(), mHalDeviceId, token, + receiver, realUserId, groupId, opId, restricted, opPackageName) { + @Override + public boolean handleFailedAttempt() { + mFailedAttempts++; + if (inLockoutMode()) { + // Failing multiple times will continue to push out the lockout time. + scheduleLockoutReset(); + return true; } - token = null; + return false; } - receiver = null; - } - @Override - public void binderDied() { - token = null; - removeClient(this); - receiver = null; - } - - @Override - protected void finalize() throws Throwable { - try { - if (token != null) { - if (DEBUG) Slog.w(TAG, "removing leaked reference: " + token); - removeClient(this); - } - } finally { - super.finalize(); + @Override + public void resetFailedAttempts() { + FingerprintService.this.resetFailedAttempts(); } - } - /* - * @return true if we're done. - */ - private boolean sendRemoved(int fingerId, int groupId) { - if (receiver == null) return true; // client not listening - try { - receiver.onRemoved(mHalDeviceId, fingerId, groupId); - return fingerId == 0; - } catch (RemoteException e) { - Slog.w(TAG, "Failed to notify Removed:", e); + @Override + public void notifyUserActivity() { + FingerprintService.this.userActivity(); } - return false; - } - /* - * @return true if we're done. - */ - private boolean sendEnrollResult(int fpId, int groupId, int remaining) { - if (receiver == null) return true; // client not listening - FingerprintUtils.vibrateFingerprintSuccess(getContext()); - MetricsLogger.action(mContext, MetricsEvent.ACTION_FINGERPRINT_ENROLL); - try { - receiver.onEnrollResult(mHalDeviceId, fpId, groupId, remaining); - return remaining == 0; - } catch (RemoteException e) { - Slog.w(TAG, "Failed to notify EnrollResult:", e); - return true; + @Override + public IFingerprintDaemon getFingerprintDaemon() { + return FingerprintService.this.getFingerprintDaemon(); } - } + }; - /* - * @return true if we're done. - */ - private boolean sendAuthenticated(int fpId, int groupId) { - boolean result = false; - boolean authenticated = fpId != 0; - if (receiver != null) { - try { - MetricsLogger.action(mContext, MetricsEvent.ACTION_FINGERPRINT_AUTH, - authenticated); - if (!authenticated) { - receiver.onAuthenticationFailed(mHalDeviceId); - } else { - if (DEBUG) { - Slog.v(TAG, "onAuthenticated(owner=" + mAuthClient.owner - + ", id=" + fpId + ", gp=" + groupId + ")"); - } - Fingerprint fp = !restricted ? - new Fingerprint("" /* TODO */, groupId, fpId, mHalDeviceId) : null; - receiver.onAuthenticationSucceeded(mHalDeviceId, fp); - } - } catch (RemoteException e) { - Slog.w(TAG, "Failed to notify Authenticated:", e); - result = true; // client failed - } - } else { - result = true; // client not listening - } - if (fpId == 0) { - if (receiver != null) { - FingerprintUtils.vibrateFingerprintError(getContext()); - } - result |= handleFailedAttempt(this); - } else { - if (receiver != null) { - FingerprintUtils.vibrateFingerprintSuccess(getContext()); - } - result |= true; // we have a valid fingerprint - resetFailedAttempts(); + if (inLockoutMode()) { + Slog.v(TAG, "In lockout mode; disallowing authentication"); + // Don't bother starting the client. Just send the error message. + if (!client.onError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) { + Slog.w(TAG, "Cannot send timeout message to client"); } - return result; + return; } + startClient(client, true /* initiatedByClient */); + } - /* - * @return true if we're done. - */ - private boolean sendAcquired(int acquiredInfo) { - if (receiver == null) return true; // client not listening - try { - receiver.onAcquired(mHalDeviceId, acquiredInfo); - return false; // acquisition continues... - } catch (RemoteException e) { - Slog.w(TAG, "Failed to invoke sendAcquired:", e); - return true; // client failed - } - finally { - // Good scans will keep the device awake - if (acquiredInfo == FINGERPRINT_ACQUIRED_GOOD) { - userActivity(); - } + private void startEnrollment(IBinder token, byte [] cryptoToken, int userId, int groupId, + IFingerprintServiceReceiver receiver, int flags, boolean restricted, + String opPackageName) { + updateActiveGroup(groupId, opPackageName); + + EnrollClient client = new EnrollClient(getContext(), mHalDeviceId, token, receiver, + userId, groupId, cryptoToken, restricted, opPackageName) { + + @Override + public IFingerprintDaemon getFingerprintDaemon() { + return FingerprintService.this.getFingerprintDaemon(); } - } - /* - * @return true if we're done. - */ - private boolean sendError(int error) { - if (receiver != null) { - try { - receiver.onError(mHalDeviceId, error); - } catch (RemoteException e) { - Slog.w(TAG, "Failed to invoke sendError:", e); - } + @Override + public void notifyUserActivity() { + FingerprintService.this.userActivity(); } - return true; // errors always terminate progress + }; + startClient(client, true /* initiatedByClient */); + } + + protected void resetFailedAttempts() { + if (DEBUG && inLockoutMode()) { + Slog.v(TAG, "Reset fingerprint lockout"); } + mFailedAttempts = 0; + // If we're asked to reset failed attempts externally (i.e. from Keyguard), + // the alarm might still be pending; remove it. + cancelLockoutReset(); + notifyLockoutResetMonitors(); } private class FingerprintServiceLockoutResetMonitor { @@ -876,8 +668,6 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe }; private final class FingerprintServiceWrapper extends IFingerprintService.Stub { - private static final String KEYGUARD_PACKAGE = "com.android.systemui"; - @Override // Binder call public long preEnroll(IBinder token) { checkPermission(MANAGE_FINGERPRINT); @@ -892,7 +682,8 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe @Override // Binder call public void enroll(final IBinder token, final byte[] cryptoToken, final int groupId, - final IFingerprintServiceReceiver receiver, final int flags) { + final IFingerprintServiceReceiver receiver, final int flags, + final String opPackageName) { checkPermission(MANAGE_FINGERPRINT); final int limit = mContext.getResources().getInteger( com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser); @@ -903,7 +694,6 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe Slog.w(TAG, "Too many fingerprints registered"); return; } - final byte [] cryptoClone = Arrays.copyOf(cryptoToken, cryptoToken.length); // Group ID is arbitrarily set to parent profile user ID. It just represents // the default fingerprints for the user. @@ -915,7 +705,8 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe mHandler.post(new Runnable() { @Override public void run() { - startEnrollment(token, cryptoClone, groupId, receiver, flags, restricted); + startEnrollment(token, cryptoToken, userId, groupId, receiver, flags, + restricted, opPackageName); } }); } @@ -932,7 +723,10 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe mHandler.post(new Runnable() { @Override public void run() { - stopEnrollment(token, true); + ClientMonitor client = mCurrentClient; + if (client instanceof EnrollClient && client.getToken() == token) { + client.stop(client.getToken() == token); + } } }); } @@ -941,17 +735,18 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe public void authenticate(final IBinder token, final long opId, final int groupId, final IFingerprintServiceReceiver receiver, final int flags, final String opPackageName) { - if (!canUseFingerprint(opPackageName, true /* foregroundOnly */)) { - if (DEBUG) Slog.v(TAG, "authenticate(): reject " + opPackageName); - return; - } final int realUserId = Binder.getCallingUid(); - + final int pid = Binder.getCallingPid(); final boolean restricted = isRestricted(); mHandler.post(new Runnable() { @Override public void run() { MetricsLogger.histogram(mContext, "fingerprint_token", opId != 0L ? 1 : 0); + if (!canUseFingerprint(opPackageName, true /* foregroundOnly */, + realUserId, pid)) { + if (DEBUG) Slog.v(TAG, "authenticate(): reject " + opPackageName); + return; + } startAuthentication(token, opId, realUserId, groupId, receiver, flags, restricted, opPackageName); } @@ -959,14 +754,29 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe } @Override // Binder call - public void cancelAuthentication(final IBinder token, String opPackageName) { - if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) { - return; - } + public void cancelAuthentication(final IBinder token, final String opPackageName) { + final int uid = Binder.getCallingUid(); + final int pid = Binder.getCallingPid(); mHandler.post(new Runnable() { @Override public void run() { - stopAuthentication(token, true); + if (!canUseFingerprint(opPackageName, true /* foregroundOnly */, uid, pid)) { + if (DEBUG) Slog.v(TAG, "cancelAuthentication(): reject " + opPackageName); + } else { + ClientMonitor client = mCurrentClient; + if (client instanceof AuthenticationClient) { + if (client.getToken() == token) { + if (DEBUG) Slog.v(TAG, "stop client " + client.getOwnerString()); + client.stop(client.getToken() == token); + } else { + if (DEBUG) Slog.v(TAG, "can't stop client " + + client.getOwnerString() + " since tokens don't match"); + } + } else if (client != null) { + if (DEBUG) Slog.v(TAG, "can't cancel non-authenticating client " + + client.getOwnerString()); + } + } } }); } @@ -987,10 +797,11 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe final IFingerprintServiceReceiver receiver) { checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission final boolean restricted = isRestricted(); + final int realUserId = Binder.getCallingUid(); mHandler.post(new Runnable() { @Override public void run() { - startRemove(token, fingerId, groupId, receiver, restricted); + startRemove(token, fingerId, realUserId, groupId, receiver, restricted); } }); @@ -998,7 +809,8 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe @Override // Binder call public boolean isHardwareDetected(long deviceId, String opPackageName) { - if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) { + if (!canUseFingerprint(opPackageName, false /* foregroundOnly */, + Binder.getCallingUid(), Binder.getCallingPid())) { return false; } return mHalDeviceId != 0; @@ -1021,7 +833,8 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe @Override // Binder call public List<Fingerprint> getEnrolledFingerprints(int userId, String opPackageName) { - if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) { + if (!canUseFingerprint(opPackageName, false /* foregroundOnly */, + Binder.getCallingUid(), Binder.getCallingPid())) { return Collections.emptyList(); } if (!isCurrentUserOrProfile(userId)) { @@ -1033,7 +846,8 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe @Override // Binder call public boolean hasEnrolledFingerprints(int userId, String opPackageName) { - if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) { + if (!canUseFingerprint(opPackageName, false /* foregroundOnly */, + Binder.getCallingUid(), Binder.getCallingPid())) { return false; } @@ -1061,7 +875,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe // The permission check should be restored once Android Keystore no longer invokes this // method from inside app processes. - return FingerprintService.this.getAuthenticatorId(); + return FingerprintService.this.getAuthenticatorId(opPackageName); } @Override // Binder call @@ -1154,6 +968,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe } daemon.setActiveGroup(userId, fpDir.getAbsolutePath().getBytes()); mCurrentUserId = userId; + mCurrentAuthenticatorId = daemon.getAuthenticatorId(); } } catch (RemoteException e) { Slog.e(TAG, "Failed to setActiveGroup():", e); @@ -1204,14 +1019,12 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe } } - public long getAuthenticatorId() { - IFingerprintDaemon daemon = getFingerprintDaemon(); - if (daemon != null) { - try { - return daemon.getAuthenticatorId(); - } catch (RemoteException e) { - Slog.e(TAG, "getAuthenticatorId failed", e); - } + public long getAuthenticatorId(String opPackageName) { + if (canUseFingerprint(opPackageName, false /* foregroundOnly */, + Binder.getCallingUid(), Binder.getCallingPid())) { + return mCurrentAuthenticatorId; + } else { + Slog.w(TAG, "Client isn't current, returning authenticator_id=0"); } return 0; } diff --git a/services/core/java/com/android/server/fingerprint/RemovalClient.java b/services/core/java/com/android/server/fingerprint/RemovalClient.java new file mode 100644 index 000000000000..69a96e127ef7 --- /dev/null +++ b/services/core/java/com/android/server/fingerprint/RemovalClient.java @@ -0,0 +1,117 @@ +/** + * Copyright (C) 2016 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.fingerprint; + +import android.content.Context; +import android.hardware.fingerprint.FingerprintManager; +import android.hardware.fingerprint.IFingerprintDaemon; +import android.hardware.fingerprint.IFingerprintServiceReceiver; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.UserHandle; +import android.util.Slog; + +/** + * A class to keep track of the remove state for a given client. + */ +public abstract class RemovalClient extends ClientMonitor { + private int mFingerId; + private int mUserIdForRemove; + + public RemovalClient(Context context, long halDeviceId, IBinder token, + IFingerprintServiceReceiver receiver, int userId, int groupId, int fingerId, + boolean restricted, String owner) { + super(context, halDeviceId, token, receiver, userId, groupId, restricted, owner); + mFingerId = fingerId; + mUserIdForRemove = userId; + } + + @Override + public int start() { + IFingerprintDaemon daemon = getFingerprintDaemon(); + // The fingerprint template ids will be removed when we get confirmation from the HAL + try { + final int result = daemon.remove(mFingerId, getUserId()); + if (result != 0) { + Slog.w(TAG, "startRemove with id = " + mFingerId + " failed, result=" + result); + onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE); + return result; + } + } catch (RemoteException e) { + Slog.e(TAG, "startRemove failed", e); + } + return 0; + } + + @Override + public int stop(boolean initiatedByClient) { + // We don't actually stop remove, but inform the client that the cancel operation succeeded + // so we can start the next operation. + if (initiatedByClient) { + onError(FingerprintManager.FINGERPRINT_ERROR_CANCELED); + } + return 0; + } + + /* + * @return true if we're done. + */ + private boolean sendRemoved(int fingerId, int groupId) { + IFingerprintServiceReceiver receiver = getReceiver(); + if (receiver == null) + return true; // client not listening + try { + receiver.onRemoved(getHalDeviceId(), fingerId, groupId); + return fingerId == 0; + } catch (RemoteException e) { + Slog.w(TAG, "Failed to notify Removed:", e); + } + return false; + } + + @Override + public boolean onRemoved(int fingerId, int groupId) { + if (fingerId != 0) { + if (fingerId != mFingerId) + FingerprintUtils.getInstance().removeFingerprintIdForUser(getContext(), fingerId, + mUserIdForRemove); + } else { + mUserIdForRemove = UserHandle.USER_NULL; + } + return sendRemoved(fingerId, getGroupId()); + } + + @Override + public boolean onEnrollResult(int fingerId, int groupId, int rem) { + if (DEBUG) Slog.w(TAG, "onEnrollResult() called for remove!"); + return true; // Invalid for Remove + } + + @Override + public boolean onAuthenticated(int fingerId, int groupId) { + if (DEBUG) Slog.w(TAG, "onAuthenticated() called for remove!"); + return true; // Invalid for Remove. + } + + @Override + public boolean onEnumerationResult(int fingerId, int groupId) { + if (DEBUG) Slog.w(TAG, "onEnumerationResult() called for remove!"); + return false; // Invalid for Remove. + } + + +} diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index fed7e4b7a8f9..e07d72f0e7d1 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -1189,7 +1189,9 @@ public final class HdmiControlService extends SystemService { @Override public void binderDied() { synchronized (mLock) { - mRecordListenerRecord = null; + if (mRecordListenerRecord == this) { + mRecordListenerRecord = null; + } } } } @@ -1813,7 +1815,9 @@ public final class HdmiControlService extends SystemService { @Override public void binderDied() { synchronized (mLock) { - mInputChangeListenerRecord = null; + if (mInputChangeListenerRecord == this) { + mInputChangeListenerRecord = null; + } } } } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index c24860886d72..3fb786bc599e 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -260,6 +260,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private static final int MSG_ADVISE_PERSIST_THRESHOLD = 7; private static final int MSG_SCREEN_ON_CHANGED = 8; private static final int MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED = 9; + private static final int MSG_UPDATE_INTERFACE_QUOTA = 10; + private static final int MSG_REMOVE_INTERFACE_QUOTA = 11; private final Context mContext; private final IActivityManager mActivityManager; @@ -1275,8 +1277,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } for (String iface : ifaces) { - removeInterfaceQuota(iface); - setInterfaceQuota(iface, quotaBytes); + // long quotaBytes split up into two ints to fit in message + mHandler.obtainMessage(MSG_UPDATE_INTERFACE_QUOTA, + (int) (quotaBytes >> 32), (int) (quotaBytes & 0xFFFFFFFF), iface) + .sendToTarget(); newMeteredIfaces.add(iface); } } @@ -1292,8 +1296,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { for (int i = connIfaces.size()-1; i >= 0; i--) { String iface = connIfaces.valueAt(i); - removeInterfaceQuota(iface); - setInterfaceQuota(iface, Long.MAX_VALUE); + // long quotaBytes split up into two ints to fit in message + mHandler.obtainMessage(MSG_UPDATE_INTERFACE_QUOTA, + (int) (Long.MAX_VALUE >> 32), (int) (Long.MAX_VALUE & 0xFFFFFFFF), iface) + .sendToTarget(); newMeteredIfaces.add(iface); } @@ -1303,7 +1309,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { for (int i = mMeteredIfaces.size() - 1; i >= 0; i--) { final String iface = mMeteredIfaces.valueAt(i); if (!newMeteredIfaces.contains(iface)) { - removeInterfaceQuota(iface); + mHandler.obtainMessage(MSG_REMOVE_INTERFACE_QUOTA, iface) + .sendToTarget(); } } mMeteredIfaces = newMeteredIfaces; @@ -2950,6 +2957,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { updateScreenOn(); return true; } + case MSG_UPDATE_INTERFACE_QUOTA: { + removeInterfaceQuota((String) msg.obj); + // int params need to be stitched back into a long + setInterfaceQuota((String) msg.obj, + ((long) msg.arg1 << 32) | (msg.arg2 & 0xFFFFFFFFL)); + return true; + } + case MSG_REMOVE_INTERFACE_QUOTA: { + removeInterfaceQuota((String) msg.obj); + return true; + } default: { return false; } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 1fb260d3864a..dc81c6561d2a 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -2315,24 +2315,29 @@ public class PackageManagerService extends IPackageManager.Stub { // For security and version matching reason, only consider // overlay packages if they reside in VENDOR_OVERLAY_DIR. File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR); - scanDirTracedLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM - | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_OVERLAY, 0); + scanDirTracedLI(vendorOverlayDir, mDefParseFlags + | PackageParser.PARSE_IS_SYSTEM + | PackageParser.PARSE_IS_SYSTEM_DIR + | PackageParser.PARSE_TRUSTED_OVERLAY, scanFlags | SCAN_TRUSTED_OVERLAY, 0); // Find base frameworks (resource packages without code). - scanDirTracedLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM + scanDirTracedLI(frameworkDir, mDefParseFlags + | PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR | PackageParser.PARSE_IS_PRIVILEGED, scanFlags | SCAN_NO_DEX, 0); // Collected privileged system packages. final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app"); - scanDirTracedLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM + scanDirTracedLI(privilegedAppDir, mDefParseFlags + | PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0); // Collect ordinary system packages. final File systemAppDir = new File(Environment.getRootDirectory(), "app"); - scanDirTracedLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM + scanDirTracedLI(systemAppDir, mDefParseFlags + | PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0); // Collect all vendor packages. @@ -2342,12 +2347,14 @@ public class PackageManagerService extends IPackageManager.Stub { } catch (IOException e) { // failed to look up canonical path, continue with original one } - scanDirTracedLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM + scanDirTracedLI(vendorAppDir, mDefParseFlags + | PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0); // Collect all OEM packages. final File oemAppDir = new File(Environment.getOemDirectory(), "app"); - scanDirTracedLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM + scanDirTracedLI(oemAppDir, mDefParseFlags + | PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0); // Prune any system packages that no longer exist. @@ -2428,10 +2435,12 @@ public class PackageManagerService extends IPackageManager.Stub { SystemClock.uptimeMillis()); scanDirTracedLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0); - scanDirTracedLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK, + scanDirTracedLI(mDrmAppPrivateInstallDir, mDefParseFlags + | PackageParser.PARSE_FORWARD_LOCK, scanFlags | SCAN_REQUIRE_KNOWN, 0); - scanDirLI(mEphemeralInstallDir, PackageParser.PARSE_IS_EPHEMERAL, + scanDirLI(mEphemeralInstallDir, mDefParseFlags + | PackageParser.PARSE_IS_EPHEMERAL, scanFlags | SCAN_REQUIRE_KNOWN, 0); /** @@ -2476,7 +2485,7 @@ public class PackageManagerService extends IPackageManager.Stub { logCriticalInfo(Log.WARN, "Expected better " + packageName + " but never showed up; reverting to system"); - final int reparseFlags; + int reparseFlags = mDefParseFlags; if (FileUtils.contains(privilegedAppDir, scanFile)) { reparseFlags = PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR @@ -6501,7 +6510,7 @@ public class PackageManagerService extends IPackageManager.Stub { return true; } - private void scanDirTracedLI(File dir, int parseFlags, int scanFlags, long currentTime) { + private void scanDirTracedLI(File dir, final int parseFlags, int scanFlags, long currentTime) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir"); try { scanDirLI(dir, parseFlags, scanFlags, currentTime); @@ -6510,7 +6519,7 @@ public class PackageManagerService extends IPackageManager.Stub { } } - private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) { + private void scanDirLI(File dir, final int parseFlags, int scanFlags, long currentTime) { final File[] files = dir.listFiles(); if (ArrayUtils.isEmpty(files)) { Log.d(TAG, "No files in app dir " + dir); @@ -6576,7 +6585,7 @@ public class PackageManagerService extends IPackageManager.Stub { } private void collectCertificatesLI(PackageSetting ps, PackageParser.Package pkg, File srcFile, - int parseFlags) throws PackageManagerException { + final int policyFlags) throws PackageManagerException { if (ps != null && ps.codePath.equals(srcFile) && ps.timeStamp == srcFile.lastModified() @@ -6605,7 +6614,7 @@ public class PackageManagerService extends IPackageManager.Stub { } try { - PackageParser.collectCertificates(pkg, parseFlags); + PackageParser.collectCertificates(pkg, policyFlags); } catch (PackageParserException e) { throw PackageManagerException.from(e); } @@ -6615,8 +6624,8 @@ public class PackageManagerService extends IPackageManager.Stub { * Traces a package scan. * @see #scanPackageLI(File, int, int, long, UserHandle) */ - private PackageParser.Package scanPackageTracedLI(File scanFile, int parseFlags, int scanFlags, - long currentTime, UserHandle user) throws PackageManagerException { + private PackageParser.Package scanPackageTracedLI(File scanFile, final int parseFlags, + int scanFlags, long currentTime, UserHandle user) throws PackageManagerException { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage"); try { return scanPackageLI(scanFile, parseFlags, scanFlags, currentTime, user); @@ -6632,7 +6641,6 @@ public class PackageManagerService extends IPackageManager.Stub { private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags, long currentTime, UserHandle user) throws PackageManagerException { if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile); - parseFlags |= mDefParseFlags; PackageParser pp = new PackageParser(); pp.setSeparateProcesses(mSeparateProcesses); pp.setOnlyCoreApps(mOnlyCore); @@ -6642,11 +6650,14 @@ public class PackageManagerService extends IPackageManager.Stub { parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY; } + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage"); final PackageParser.Package pkg; try { pkg = pp.parsePackage(scanFile, parseFlags); } catch (PackageParserException e) { throw PackageManagerException.from(e); + } finally { + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } return scanPackageLI(pkg, scanFile, parseFlags, scanFlags, currentTime, user); @@ -6657,7 +6668,7 @@ public class PackageManagerService extends IPackageManager.Stub { * @throws PackageManagerException on a parse error. */ private PackageParser.Package scanPackageLI(PackageParser.Package pkg, File scanFile, - int parseFlags, int scanFlags, long currentTime, UserHandle user) + final int policyFlags, int scanFlags, long currentTime, UserHandle user) throws PackageManagerException { // If the package has children and this is the first dive in the function // we scan the package with the SCAN_CHECK_ONLY flag set to see whether all @@ -6673,20 +6684,20 @@ public class PackageManagerService extends IPackageManager.Stub { } // Scan the parent - PackageParser.Package scannedPkg = scanPackageInternalLI(pkg, scanFile, parseFlags, + PackageParser.Package scannedPkg = scanPackageInternalLI(pkg, scanFile, policyFlags, scanFlags, currentTime, user); // Scan the children final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; for (int i = 0; i < childCount; i++) { PackageParser.Package childPackage = pkg.childPackages.get(i); - scanPackageInternalLI(childPackage, scanFile, parseFlags, scanFlags, + scanPackageInternalLI(childPackage, scanFile, policyFlags, scanFlags, currentTime, user); } if ((scanFlags & SCAN_CHECK_ONLY) != 0) { - return scanPackageLI(pkg, scanFile, parseFlags, scanFlags, currentTime, user); + return scanPackageLI(pkg, scanFile, policyFlags, scanFlags, currentTime, user); } return scannedPkg; @@ -6697,7 +6708,7 @@ public class PackageManagerService extends IPackageManager.Stub { * @throws PackageManagerException on a parse error. */ private PackageParser.Package scanPackageInternalLI(PackageParser.Package pkg, File scanFile, - int parseFlags, int scanFlags, long currentTime, UserHandle user) + int policyFlags, int scanFlags, long currentTime, UserHandle user) throws PackageManagerException { PackageSetting ps = null; PackageSetting updatedPkg; @@ -6724,7 +6735,7 @@ public class PackageManagerService extends IPackageManager.Stub { // may need to remove disabled child packages on the system partition // or may need to not add child packages if the parent apk is updated // on the data partition and no longer defines this child package. - if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) != 0) { + if ((policyFlags & PackageParser.PARSE_IS_SYSTEM) != 0) { // If this is a parent package for an updated system app and this system // app got an OTA update which no longer defines some of the child packages // we have to prune them from the disabled system packages. @@ -6754,7 +6765,7 @@ public class PackageManagerService extends IPackageManager.Stub { boolean updatedPkgBetter = false; // First check if this is a system package that may involve an update - if (updatedPkg != null && (parseFlags & PackageParser.PARSE_IS_SYSTEM) != 0) { + if (updatedPkg != null && (policyFlags & PackageParser.PARSE_IS_SYSTEM) != 0) { // If new package is not located in "/system/priv-app" (e.g. due to an OTA), // it needs to drop FLAG_PRIVILEGED. if (locationIsPrivileged(scanFile)) { @@ -6836,17 +6847,17 @@ public class PackageManagerService extends IPackageManager.Stub { if (updatedPkg != null) { // An updated system app will not have the PARSE_IS_SYSTEM flag set // initially - parseFlags |= PackageParser.PARSE_IS_SYSTEM; + policyFlags |= PackageParser.PARSE_IS_SYSTEM; // An updated privileged app will not have the PARSE_IS_PRIVILEGED // flag set initially if ((updatedPkg.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) { - parseFlags |= PackageParser.PARSE_IS_PRIVILEGED; + policyFlags |= PackageParser.PARSE_IS_PRIVILEGED; } } // Verify certificates against what was last scanned - collectCertificatesLI(ps, pkg, scanFile, parseFlags); + collectCertificatesLI(ps, pkg, scanFile, policyFlags); /* * A new system app appeared, but we already had a non-system one of the @@ -6854,7 +6865,7 @@ public class PackageManagerService extends IPackageManager.Stub { */ boolean shouldHideSystemApp = false; if (updatedPkg == null && ps != null - && (parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0 && !isSystemApp(ps)) { + && (policyFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0 && !isSystemApp(ps)) { /* * Check to make sure the signatures match first. If they don't, * wipe the installed application and its data. @@ -6902,16 +6913,16 @@ public class PackageManagerService extends IPackageManager.Stub { // are kept in different files. (except for app in either system or // vendor path). // TODO grab this value from PackageSettings - if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { + if ((policyFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { if (ps != null && !ps.codePath.equals(ps.resourcePath)) { - parseFlags |= PackageParser.PARSE_FORWARD_LOCK; + policyFlags |= PackageParser.PARSE_FORWARD_LOCK; } } // TODO: extend to support forward-locked splits String resourcePath = null; String baseResourcePath = null; - if ((parseFlags & PackageParser.PARSE_FORWARD_LOCK) != 0 && !updatedPkgBetter) { + if ((policyFlags & PackageParser.PARSE_FORWARD_LOCK) != 0 && !updatedPkgBetter) { if (ps != null && ps.resourcePathString != null) { resourcePath = ps.resourcePathString; baseResourcePath = ps.resourcePathString; @@ -6934,7 +6945,7 @@ public class PackageManagerService extends IPackageManager.Stub { pkg.setApplicationInfoSplitResourcePaths(pkg.splitCodePaths); // Note that we invoke the following method only if we are about to unpack an application - PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanFlags + PackageParser.Package scannedPkg = scanPackageLI(pkg, policyFlags, scanFlags | SCAN_UPDATE_SIGNATURE, currentTime, user); /* @@ -7576,8 +7587,9 @@ public class PackageManagerService extends IPackageManager.Stub { return cpuAbiOverride; } - private PackageParser.Package scanPackageTracedLI(PackageParser.Package pkg, int parseFlags, - int scanFlags, long currentTime, UserHandle user) throws PackageManagerException { + private PackageParser.Package scanPackageTracedLI(PackageParser.Package pkg, + final int policyFlags, int scanFlags, long currentTime, UserHandle user) + throws PackageManagerException { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage"); // If the package has children and this is the first dive in the function // we recursively scan the package with the SCAN_CHECK_ONLY flag set to see @@ -7595,12 +7607,12 @@ public class PackageManagerService extends IPackageManager.Stub { final PackageParser.Package scannedPkg; try { // Scan the parent - scannedPkg = scanPackageLI(pkg, parseFlags, scanFlags, currentTime, user); + scannedPkg = scanPackageLI(pkg, policyFlags, scanFlags, currentTime, user); // Scan the children final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; for (int i = 0; i < childCount; i++) { PackageParser.Package childPkg = pkg.childPackages.get(i); - scanPackageLI(childPkg, parseFlags, + scanPackageLI(childPkg, policyFlags, scanFlags, currentTime, user); } } finally { @@ -7608,17 +7620,17 @@ public class PackageManagerService extends IPackageManager.Stub { } if ((scanFlags & SCAN_CHECK_ONLY) != 0) { - return scanPackageTracedLI(pkg, parseFlags, scanFlags, currentTime, user); + return scanPackageTracedLI(pkg, policyFlags, scanFlags, currentTime, user); } return scannedPkg; } - private PackageParser.Package scanPackageLI(PackageParser.Package pkg, int parseFlags, + private PackageParser.Package scanPackageLI(PackageParser.Package pkg, final int policyFlags, int scanFlags, long currentTime, UserHandle user) throws PackageManagerException { boolean success = false; try { - final PackageParser.Package res = scanPackageDirtyLI(pkg, parseFlags, scanFlags, + final PackageParser.Package res = scanPackageDirtyLI(pkg, policyFlags, scanFlags, currentTime, user); success = true; return res; @@ -7632,8 +7644,8 @@ public class PackageManagerService extends IPackageManager.Stub { } } - private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg, int parseFlags, - int scanFlags, long currentTime, UserHandle user) + private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg, + final int policyFlags, final int scanFlags, long currentTime, UserHandle user) throws PackageManagerException { final File scanFile = new File(pkg.codePath); if (pkg.applicationInfo.getCodePath() == null || @@ -7643,14 +7655,36 @@ public class PackageManagerService extends IPackageManager.Stub { "Code and resource paths haven't been set correctly"); } - if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) { + // Apply policy + if ((policyFlags&PackageParser.PARSE_IS_SYSTEM) != 0) { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; + if (pkg.applicationInfo.isDirectBootAware()) { + // we're direct boot aware; set for all components + for (PackageParser.Service s : pkg.services) { + s.info.encryptionAware = s.info.directBootAware = true; + } + for (PackageParser.Provider p : pkg.providers) { + p.info.encryptionAware = p.info.directBootAware = true; + } + for (PackageParser.Activity a : pkg.activities) { + a.info.encryptionAware = a.info.directBootAware = true; + } + for (PackageParser.Activity r : pkg.receivers) { + r.info.encryptionAware = r.info.directBootAware = true; + } + } } else { // Only allow system apps to be flagged as core apps. pkg.coreApp = false; + // clear flags not applicable to regular apps + pkg.applicationInfo.privateFlags &= + ~ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE; + pkg.applicationInfo.privateFlags &= + ~ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE; } + pkg.mTrustedOverlay = (policyFlags&PackageParser.PARSE_TRUSTED_OVERLAY) != 0; - if ((parseFlags&PackageParser.PARSE_IS_PRIVILEGED) != 0) { + if ((policyFlags&PackageParser.PARSE_IS_PRIVILEGED) != 0) { pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED; } @@ -7699,7 +7733,7 @@ public class PackageManagerService extends IPackageManager.Stub { } if (DEBUG_PACKAGE_SCANNING) { - if ((parseFlags & PackageParser.PARSE_CHATTY) != 0) + if ((policyFlags & PackageParser.PARSE_CHATTY) != 0) Log.d(TAG, "Scanning package " + pkg.packageName); } @@ -7774,7 +7808,7 @@ public class PackageManagerService extends IPackageManager.Stub { + " for shared user failed"); } if (DEBUG_PACKAGE_SCANNING) { - if ((parseFlags & PackageParser.PARSE_CHATTY) != 0) + if ((policyFlags & PackageParser.PARSE_CHATTY) != 0) Log.d(TAG, "Shared UserID " + pkg.mSharedUserId + " (uid=" + suid.userId + "): packages=" + suid.packages); } @@ -7820,6 +7854,7 @@ public class PackageManagerService extends IPackageManager.Stub { origPackage = null; continue; } + // TODO: Add case when shared user id is added [b/28144775] } else { if (DEBUG_UPGRADE) Log.v(TAG, "Renaming new package " + pkg.packageName + " to old name " + origPackage.name); @@ -7886,7 +7921,7 @@ public class PackageManagerService extends IPackageManager.Stub { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; } - if ((parseFlags&PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { + if ((policyFlags&PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { // Check all shared libraries and map to their actual file path. // We only do this here for apps not on a system dir, because those // are the only ones that can fail an install due to this. We @@ -7907,7 +7942,7 @@ public class PackageManagerService extends IPackageManager.Stub { // over the latest parsed certs. pkgSetting.signatures.mSignatures = pkg.mSignatures; } else { - if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { + if ((policyFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package " + pkg.packageName + " upgrade keys do not match the " + "previously installed version"); @@ -7925,7 +7960,7 @@ public class PackageManagerService extends IPackageManager.Stub { // over the latest parsed certs. pkgSetting.signatures.mSignatures = pkg.mSignatures; } catch (PackageManagerException e) { - if ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { + if ((policyFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) { throw e; } // The signature has changed, but this package is in the system @@ -8114,7 +8149,7 @@ public class PackageManagerService extends IPackageManager.Stub { // Only privileged apps and updated privileged apps can add child packages. if (pkg.childPackages != null && !pkg.childPackages.isEmpty()) { - if ((parseFlags & PARSE_IS_PRIVILEGED) == 0) { + if ((policyFlags & PARSE_IS_PRIVILEGED) == 0) { throw new PackageManagerException("Only privileged apps and updated " + "privileged apps can add child packages. Ignoring package " + pkg.packageName); @@ -8240,7 +8275,7 @@ public class PackageManagerService extends IPackageManager.Stub { } else if (pkgSetting.firstInstallTime == 0) { // We need *something*. Take time time stamp of the file. pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = scanFileTime; - } else if ((parseFlags&PackageParser.PARSE_IS_SYSTEM_DIR) != 0) { + } else if ((policyFlags&PackageParser.PARSE_IS_SYSTEM_DIR) != 0) { if (scanFileTime != pkgSetting.timeStamp) { // A package on the system image has changed; consider this // to be an update. @@ -8283,7 +8318,7 @@ public class PackageManagerService extends IPackageManager.Stub { p.info.authority = p.info.authority + ";" + names[j]; } if (DEBUG_PACKAGE_SCANNING) { - if ((parseFlags & PackageParser.PARSE_CHATTY) != 0) + if ((policyFlags & PackageParser.PARSE_CHATTY) != 0) Log.d(TAG, "Registered content provider: " + names[j] + ", className = " + p.info.name + ", isSyncable = " + p.info.isSyncable); @@ -8298,7 +8333,7 @@ public class PackageManagerService extends IPackageManager.Stub { } } } - if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { + if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { @@ -8318,7 +8353,7 @@ public class PackageManagerService extends IPackageManager.Stub { s.info.processName = fixProcessName(pkg.applicationInfo.processName, s.info.processName, pkg.applicationInfo.uid); mServices.addService(s); - if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { + if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { @@ -8338,7 +8373,7 @@ public class PackageManagerService extends IPackageManager.Stub { a.info.processName = fixProcessName(pkg.applicationInfo.processName, a.info.processName, pkg.applicationInfo.uid); mReceivers.addActivity(a, "receiver"); - if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { + if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { @@ -8358,7 +8393,7 @@ public class PackageManagerService extends IPackageManager.Stub { a.info.processName = fixProcessName(pkg.applicationInfo.processName, a.info.processName, pkg.applicationInfo.uid); mActivities.addActivity(a, "activity"); - if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { + if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { @@ -8378,7 +8413,7 @@ public class PackageManagerService extends IPackageManager.Stub { PackageParser.PermissionGroup cur = mPermissionGroups.get(pg.info.name); if (cur == null) { mPermissionGroups.put(pg.info.name, pg); - if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { + if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { @@ -8390,7 +8425,7 @@ public class PackageManagerService extends IPackageManager.Stub { Slog.w(TAG, "Permission group " + pg.info.name + " from package " + pg.info.packageName + " ignored: original from " + cur.info.packageName); - if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { + if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { @@ -8469,7 +8504,7 @@ public class PackageManagerService extends IPackageManager.Stub { bp.uid = pkg.applicationInfo.uid; bp.sourcePackage = p.info.packageName; p.info.flags |= PermissionInfo.FLAG_INSTALLED; - if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { + if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { @@ -8488,7 +8523,7 @@ public class PackageManagerService extends IPackageManager.Stub { + p.info.packageName + " ignored: original from " + bp.sourcePackage); } - } else if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { + } else if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { @@ -8523,7 +8558,7 @@ public class PackageManagerService extends IPackageManager.Stub { // need other information about the application, like the ABI and what not ? a.info.nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir; mInstrumentation.put(a.getComponentName(), a); - if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { + if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { @@ -13538,8 +13573,8 @@ public class PackageManagerService extends IPackageManager.Stub { /* * Install a non-existing package. */ - private void installNewPackageLIF(PackageParser.Package pkg, int parseFlags, int scanFlags, - UserHandle user, String installerPackageName, String volumeUuid, + private void installNewPackageLIF(PackageParser.Package pkg, final int policyFlags, + int scanFlags, UserHandle user, String installerPackageName, String volumeUuid, PackageInstalledInfo res) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installNewPackage"); @@ -13568,7 +13603,7 @@ public class PackageManagerService extends IPackageManager.Stub { } try { - PackageParser.Package newPackage = scanPackageTracedLI(pkg, parseFlags, scanFlags, + PackageParser.Package newPackage = scanPackageTracedLI(pkg, policyFlags, scanFlags, System.currentTimeMillis(), user); updateSettingsLI(newPackage, installerPackageName, null, res, user); @@ -13625,9 +13660,9 @@ public class PackageManagerService extends IPackageManager.Stub { return false; } - private void replacePackageLIF(PackageParser.Package pkg, int parseFlags, int scanFlags, + private void replacePackageLIF(PackageParser.Package pkg, final int policyFlags, int scanFlags, UserHandle user, String installerPackageName, PackageInstalledInfo res) { - final boolean isEphemeral = (parseFlags & PackageParser.PARSE_IS_EPHEMERAL) != 0; + final boolean isEphemeral = (policyFlags & PackageParser.PARSE_IS_EPHEMERAL) != 0; final PackageParser.Package oldPackage; final String pkgName = pkg.packageName; @@ -13715,10 +13750,18 @@ public class PackageManagerService extends IPackageManager.Stub { boolean sysPkg = (isSystemApp(oldPackage)); if (sysPkg) { - replaceSystemPackageLIF(oldPackage, pkg, parseFlags, scanFlags, + // Set the system/privileged flags as needed + final boolean privileged = + (oldPackage.applicationInfo.privateFlags + & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; + final int systemPolicyFlags = policyFlags + | PackageParser.PARSE_IS_SYSTEM + | (privileged ? PackageParser.PARSE_IS_PRIVILEGED : 0); + + replaceSystemPackageLIF(oldPackage, pkg, systemPolicyFlags, scanFlags, user, allUsers, installerPackageName, res); } else { - replaceNonSystemPackageLIF(oldPackage, pkg, parseFlags, scanFlags, + replaceNonSystemPackageLIF(oldPackage, pkg, policyFlags, scanFlags, user, allUsers, installerPackageName, res); } } @@ -13733,7 +13776,7 @@ public class PackageManagerService extends IPackageManager.Stub { } private void replaceNonSystemPackageLIF(PackageParser.Package deletedPackage, - PackageParser.Package pkg, int parseFlags, int scanFlags, UserHandle user, + PackageParser.Package pkg, final int policyFlags, int scanFlags, UserHandle user, int[] allUsers, String installerPackageName, PackageInstalledInfo res) { if (DEBUG_INSTALL) Slog.d(TAG, "replaceNonSystemPackageLI: new=" + pkg + ", old=" + deletedPackage); @@ -13775,7 +13818,7 @@ public class PackageManagerService extends IPackageManager.Stub { clearAppProfilesLIF(pkg); try { - final PackageParser.Package newPackage = scanPackageTracedLI(pkg, parseFlags, + final PackageParser.Package newPackage = scanPackageTracedLI(pkg, policyFlags, scanFlags | SCAN_UPDATE_TIME, System.currentTimeMillis(), user); updateSettingsLI(newPackage, installerPackageName, allUsers, res, user); @@ -13872,20 +13915,13 @@ public class PackageManagerService extends IPackageManager.Stub { } private void replaceSystemPackageLIF(PackageParser.Package deletedPackage, - PackageParser.Package pkg, int parseFlags, int scanFlags, UserHandle user, + PackageParser.Package pkg, final int policyFlags, int scanFlags, UserHandle user, int[] allUsers, String installerPackageName, PackageInstalledInfo res) { if (DEBUG_INSTALL) Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg + ", old=" + deletedPackage); final boolean disabledSystem; - // Set the system/privileged flags as needed - parseFlags |= PackageParser.PARSE_IS_SYSTEM; - if ((deletedPackage.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) - != 0) { - parseFlags |= PackageParser.PARSE_IS_PRIVILEGED; - } - // Remove existing system package removePackageLI(deletedPackage, true); @@ -13914,7 +13950,7 @@ public class PackageManagerService extends IPackageManager.Stub { PackageParser.Package newPackage = null; try { // Add the package to the internal data structures - newPackage = scanPackageTracedLI(pkg, parseFlags, scanFlags, 0, user); + newPackage = scanPackageTracedLI(pkg, policyFlags, scanFlags, 0, user); // Set the update and install times PackageSetting deletedPkgSetting = (PackageSetting) deletedPackage.mExtras; @@ -13967,7 +14003,7 @@ public class PackageManagerService extends IPackageManager.Stub { } // Add back the old system package try { - scanPackageTracedLI(deletedPackage, parseFlags, SCAN_UPDATE_SIGNATURE, 0, user); + scanPackageTracedLI(deletedPackage, policyFlags, SCAN_UPDATE_SIGNATURE, 0, user); } catch (PackageManagerException e) { Slog.e(TAG, "Failed to restore original package: " + e.getMessage()); } @@ -15296,7 +15332,10 @@ public class PackageManagerService extends IPackageManager.Stub { // Install the system package if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs); - int parseFlags = PackageParser.PARSE_MUST_BE_APK | PackageParser.PARSE_IS_SYSTEM; + int parseFlags = mDefParseFlags + | PackageParser.PARSE_MUST_BE_APK + | PackageParser.PARSE_IS_SYSTEM + | PackageParser.PARSE_IS_SYSTEM_DIR; if (locationIsPrivileged(disabledPs.codePath)) { parseFlags |= PackageParser.PARSE_IS_PRIVILEGED; } diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index ac6510ae57ac..0ac5c1fef30c 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -907,6 +907,16 @@ public class ShortcutService extends IShortcutService.Stub { } } + public void cleanupBitmapsForPackage(@UserIdInt int userId, String packageName) { + final File packagePath = new File(getUserBitmapFilePath(userId), packageName); + if (!packagePath.isDirectory()) { + return; + } + if (!(FileUtils.deleteContents(packagePath) && packagePath.delete())) { + Slog.w(TAG, "Unable to remove directory " + packagePath); + } + } + @VisibleForTesting static class FileOutputStreamWithPath extends FileOutputStream { private final File mFile; @@ -1572,7 +1582,7 @@ public class ShortcutService extends IShortcutService.Stub { // First, remove the package from the package list (if the package is a publisher). if (packageUserId == owningUserId) { - if (mUser.removePackage(packageName) != null) { + if (mUser.removePackage(this, packageName) != null) { doNotify = true; } } @@ -2084,11 +2094,11 @@ public class ShortcutService extends IShortcutService.Stub { pw.println(mIconPersistFormat); pw.print(" Icon quality: "); pw.println(mIconPersistQuality); - pw.print(" saveDelayMillis:"); + pw.print(" saveDelayMillis: "); pw.println(mSaveDelayMillis); - pw.print(" resetInterval:"); + pw.print(" resetInterval: "); pw.println(mResetInterval); - pw.print(" maxUpdatesPerInterval:"); + pw.print(" maxUpdatesPerInterval: "); pw.println(mMaxUpdatesPerInterval); pw.print(" maxDynamicShortcuts:"); pw.println(mMaxDynamicShortcuts); @@ -2416,7 +2426,6 @@ public class ShortcutService extends IShortcutService.Stub { return mPackageManagerInternal; } - @VisibleForTesting File getUserBitmapFilePath(@UserIdInt int userId) { return new File(injectUserDataPath(userId), DIRECTORY_BITMAPS); } diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java index 593f607f6268..0b8c3a2ee8be 100644 --- a/services/core/java/com/android/server/pm/ShortcutUser.java +++ b/services/core/java/com/android/server/pm/ShortcutUser.java @@ -18,6 +18,7 @@ package com.android.server.pm; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.content.ComponentName; +import android.text.format.Formatter; import android.util.ArrayMap; import android.util.Slog; @@ -29,6 +30,7 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; +import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.util.function.Consumer; @@ -103,8 +105,12 @@ class ShortcutUser { return mPackages; } - public ShortcutPackage removePackage(@NonNull String packageName) { - return mPackages.remove(packageName); + public ShortcutPackage removePackage(@NonNull ShortcutService s, @NonNull String packageName) { + final ShortcutPackage removed = mPackages.remove(packageName); + + s.cleanupBitmapsForPackage(mUserId, packageName); + + return removed; } public ArrayMap<PackageWithUser, ShortcutLauncher> getAllLaunchers() { @@ -279,18 +285,51 @@ class ShortcutUser { pw.print(mUserId); pw.println(); + prefix += prefix + " "; + pw.print(prefix); - pw.print(" "); pw.print("Default launcher: "); pw.print(mLauncherComponent); pw.println(); for (int i = 0; i < mLaunchers.size(); i++) { - mLaunchers.valueAt(i).dump(s, pw, prefix + " "); + mLaunchers.valueAt(i).dump(s, pw, prefix); } for (int i = 0; i < mPackages.size(); i++) { - mPackages.valueAt(i).dump(s, pw, prefix + " "); + mPackages.valueAt(i).dump(s, pw, prefix); + } + + pw.println(); + pw.print(prefix); + pw.println("Bitmap directories: "); + dumpDirectorySize(s, pw, prefix + " ", s.getUserBitmapFilePath(mUserId)); + } + + private void dumpDirectorySize(@NonNull ShortcutService s, @NonNull PrintWriter pw, + @NonNull String prefix, File path) { + int numFiles = 0; + long size = 0; + final File[] children = path.listFiles(); + if (children != null) { + for (File child : path.listFiles()) { + if (child.isFile()) { + numFiles++; + size += child.length(); + } else if (child.isDirectory()) { + dumpDirectorySize(s, pw, prefix + " ", child); + } + } } + pw.print(prefix); + pw.print("Path: "); + pw.print(path.getName()); + pw.print("/ has "); + pw.print(numFiles); + pw.print(" files, size="); + pw.print(size); + pw.print(" ("); + pw.print(Formatter.formatFileSize(s.mContext, size)); + pw.println(")"); } } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 60ea2544cadc..9b918f3fb993 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -17,6 +17,9 @@ package com.android.server.pm; +import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; +import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; + import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; @@ -27,10 +30,12 @@ import android.app.ActivityManagerInternal; import android.app.ActivityManagerNative; import android.app.IActivityManager; import android.app.IStopUserCallback; +import android.app.KeyguardManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.IntentSender; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.UserInfo; @@ -693,6 +698,37 @@ public class UserManagerService extends IUserManager.Stub { } @Override + public boolean trySetQuietModeDisabled(int userHandle, IntentSender target) { + if (mContext.getSystemService(StorageManager.class).isUserKeyUnlocked(userHandle) + || !mLockPatternUtils.isSecure(userHandle) + || !mLockPatternUtils.isSeparateProfileChallengeEnabled(userHandle)) { + // if the user is already unlocked, no need to show a profile challenge + setQuietModeEnabled(userHandle, false); + return true; + } + + long identity = Binder.clearCallingIdentity(); + try { + // otherwise, we show a profile challenge to trigger decryption of the user + final KeyguardManager km = (KeyguardManager) mContext.getSystemService( + Context.KEYGUARD_SERVICE); + final Intent unlockIntent = km.createConfirmDeviceCredentialIntent(null, null, + userHandle); + if (unlockIntent == null) { + return false; + } + if (target != null) { + unlockIntent.putExtra(Intent.EXTRA_INTENT, target); + } + unlockIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + mContext.startActivity(unlockIntent); + } finally { + Binder.restoreCallingIdentity(identity); + } + return false; + } + + @Override public void setUserEnabled(int userId) { checkManageUsersPermission("enable user"); synchronized (mPackagesLock) { diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 2e81132cebf8..8f259db4c924 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -4754,7 +4754,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Dock windows carve out the bottom of the screen, so normal windows // can't appear underneath them. if (attrs.type == TYPE_INPUT_METHOD && win.isVisibleOrBehindKeyguardLw() - && !win.getGivenInsetsPendingLw()) { + && win.isDisplayedLw() && !win.getGivenInsetsPendingLw()) { setLastInputMethodWindowLw(null, null); offsetInputMethodWindowLw(win); } diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java index 96144174f7b2..95923fe159a2 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java @@ -26,7 +26,7 @@ public interface StatusBarManagerInternal { void buzzBeepBlinked(); void notificationLightPulse(int argb, int onMillis, int offMillis); void notificationLightOff(); - void showScreenPinningRequest(); + void showScreenPinningRequest(int taskId); void showAssistDisclosure(); void startAssist(Bundle args); void onCameraLaunchGestureDetected(int source); diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index dbbaa5ebf75f..e71bdb83841b 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -153,10 +153,10 @@ public class StatusBarManagerService extends IStatusBarService.Stub { } @Override - public void showScreenPinningRequest() { + public void showScreenPinningRequest(int taskId) { if (mBar != null) { try { - mBar.showScreenPinningRequest(); + mBar.showScreenPinningRequest(taskId); } catch (RemoteException e) { } } diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index 3c84fc27141c..728e244bfb10 100644 --- a/services/core/java/com/android/server/trust/TrustManagerService.java +++ b/services/core/java/com/android/server/trust/TrustManagerService.java @@ -26,6 +26,7 @@ import org.xmlpull.v1.XmlPullParserException; import android.Manifest; import android.app.ActivityManager; +import android.app.ActivityManagerNative; import android.app.admin.DevicePolicyManager; import android.app.trust.ITrustListener; import android.app.trust.ITrustManager; @@ -318,6 +319,12 @@ public class TrustManagerService extends SystemService { synchronized (mDeviceLockedForUser) { mDeviceLockedForUser.put(userId, locked); } + if (locked) { + try { + ActivityManagerNative.getDefault().notifyLockedProfile(userId); + } catch (RemoteException e) { + } + } } } diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 4ec297e31015..545b9db75ecd 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -499,7 +499,7 @@ class AppWindowToken extends WindowToken { + " with replacing child windows."); for (int i = allAppWindows.size() - 1; i >= 0; i--) { final WindowState w = allAppWindows.get(i); - if (w.isChildWindow()) { + if (w.shouldBeReplacedWithChildren()) { w.setReplacing(false /* animate */); } } @@ -539,8 +539,9 @@ class AppWindowToken extends WindowToken { for (int i = allAppWindows.size() - 1; i >= 0; i--) { WindowState candidate = allAppWindows.get(i); if (candidate.mWillReplaceWindow && candidate.mReplacingWindow == null && - candidate.getWindowTag().equals(w.getWindowTag().toString())) { + candidate.getWindowTag().toString().equals(w.getWindowTag().toString())) { candidate.mReplacingWindow = w; + w.mSkipEnterAnimationForSeamlessReplacement = !candidate.mAnimateReplacingWindow; // if we got a replacement window, reset the timeout to give drawing more time service.mH.removeMessages(H.WINDOW_REPLACEMENT_TIMEOUT); @@ -575,6 +576,9 @@ class AppWindowToken extends WindowToken { continue; } candidate.mWillReplaceWindow = false; + if (candidate.mReplacingWindow != null) { + candidate.mReplacingWindow.mSkipEnterAnimationForSeamlessReplacement = false; + } // Since the window already timed out, remove it immediately now. // Use removeWindowInnerLocked() instead of removeWindowLocked(), as the latter // delays removal on certain conditions, which will leave the stale window in the diff --git a/services/core/java/com/android/server/wm/DimLayerController.java b/services/core/java/com/android/server/wm/DimLayerController.java index 3ec02b9f66fc..c240d0733a0a 100644 --- a/services/core/java/com/android/server/wm/DimLayerController.java +++ b/services/core/java/com/android/server/wm/DimLayerController.java @@ -169,6 +169,10 @@ class DimLayerController { + " dimLayerUser=" + dimLayerUser.toShortString() + " state.continueDimming=" + state.continueDimming + " state.dimLayer.isDimming=" + state.dimLayer.isDimming()); + if (state.animator != null && state.animator.mWin.mWillReplaceWindow) { + return; + } + if (!state.continueDimming && state.dimLayer.isDimming()) { state.animator = null; dimLayerUser.getDimBounds(mTmpBounds); @@ -303,7 +307,7 @@ class DimLayerController { applyDim(dimLayerUser, animator, true /* aboveApp */); } - private void applyDim( + void applyDim( DimLayer.DimLayerUser dimLayerUser, WindowStateAnimator animator, boolean aboveApp) { if (dimLayerUser == null) { Slog.e(TAG, "Trying to apply dim layer for: " + this diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java index ff537bef1aa9..3bd7a96182f3 100644 --- a/services/core/java/com/android/server/wm/DockedStackDividerController.java +++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java @@ -24,6 +24,7 @@ import static android.view.WindowManager.DOCKED_RIGHT; import static android.view.WindowManager.DOCKED_TOP; import static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION; import static com.android.server.wm.AppTransition.TOUCH_RESPONSE_INTERPOLATOR; +import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -38,8 +39,10 @@ import android.view.IDockedStackListener; import android.view.SurfaceControl; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; +import android.view.animation.PathInterpolator; import com.android.server.wm.DimLayer.DimLayerUser; +import com.android.server.wm.WindowManagerService.H; import java.util.ArrayList; @@ -74,6 +77,13 @@ public class DockedStackDividerController implements DimLayerUser { */ private static final float CLIP_REVEAL_MEET_FRACTION_MAX = 0.8f; + private static final Interpolator IME_ADJUST_ENTRY_INTERPOLATOR = + new PathInterpolator(0.2f, 0f, 0.1f, 1f); + + private static final long IME_ADJUST_ANIM_DURATION = 280; + + private static final long IME_ADJUST_DRAWN_TIMEOUT = 200; + private final WindowManagerService mService; private final DisplayContent mDisplayContent; private int mDividerWindowWidth; @@ -95,11 +105,13 @@ public class DockedStackDividerController implements DimLayerUser { private float mAnimationStart; private float mAnimationTarget; private long mAnimationDuration; + private boolean mAnimationStartDelayed; private final Interpolator mMinimizedDockInterpolator; private float mMaximizeMeetFraction; private final Rect mTouchRegion = new Rect(); private boolean mAnimatingForIme; private boolean mAdjustedForIme; + private WindowState mDelayedImeWin; DockedStackDividerController(WindowManagerService service, DisplayContent displayContent) { mService = service; @@ -186,10 +198,16 @@ public class DockedStackDividerController implements DimLayerUser { return mLastVisibility; } - void setAdjustedForIme(boolean adjusted, boolean animate) { + void setAdjustedForIme(boolean adjusted, boolean animate, WindowState imeWin) { if (mAdjustedForIme != adjusted) { - mAnimatingForIme = animate; mAdjustedForIme = adjusted; + if (animate) { + startImeAdjustAnimation(adjusted, imeWin); + } else { + + // Animation might be delayed, so only notify if we don't run an animation. + notifyAdjustedForImeChanged(adjusted, 0 /* duration */); + } } } @@ -283,12 +301,27 @@ public class DockedStackDividerController implements DimLayerUser { mDockedStackListeners.finishBroadcast(); } + void notifyAdjustedForImeChanged(boolean adjustedForIme, long animDuration) { + final int size = mDockedStackListeners.beginBroadcast(); + for (int i = 0; i < size; ++i) { + final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i); + try { + listener.onAdjustedForImeChanged(adjustedForIme, animDuration); + } catch (RemoteException e) { + Slog.e(TAG_WM, "Error delivering adjusted for ime changed event.", e); + } + } + mDockedStackListeners.finishBroadcast(); + } + void registerDockedStackListener(IDockedStackListener listener) { mDockedStackListeners.register(listener); notifyDockedDividerVisibilityChanged(wasVisible()); notifyDockedStackExistsChanged( mDisplayContent.mService.mStackIdToStack.get(DOCKED_STACK_ID) != null); notifyDockedStackMinimizedChanged(mMinimizedDock, 0 /* animDuration */); + notifyAdjustedForImeChanged(mAdjustedForIme, 0 /* animDuration */); + } void setResizeDimLayer(boolean visible, int targetStackId, float alpha) { @@ -371,7 +404,7 @@ public class DockedStackDividerController implements DimLayerUser { return; } - mAnimatingForIme = false; + clearImeAdjustAnimation(); if (minimizedDock) { if (animate) { startAdjustAnimation(0f, 1f); @@ -387,6 +420,17 @@ public class DockedStackDividerController implements DimLayerUser { } } + private void clearImeAdjustAnimation() { + final ArrayList<TaskStack> stacks = mDisplayContent.getStacks(); + for (int i = stacks.size() - 1; i >= 0; --i) { + final TaskStack stack = stacks.get(i); + if (stack != null && stack.isAdjustedForIme()) { + stack.resetAdjustedForIme(true /* adjustBoundsNow */); + } + } + mAnimatingForIme = false; + } + private void startAdjustAnimation(float from, float to) { mAnimatingForMinimizedDockedStack = true; mAnimationStarted = false; @@ -394,6 +438,48 @@ public class DockedStackDividerController implements DimLayerUser { mAnimationTarget = to; } + private void startImeAdjustAnimation(boolean adjusted, WindowState imeWin) { + mAnimatingForIme = true; + mAnimationStarted = false; + mAnimationStart = adjusted ? 0 : 1; + mAnimationTarget = adjusted ? 1 : 0; + + final ArrayList<TaskStack> stacks = mDisplayContent.getStacks(); + for (int i = stacks.size() - 1; i >= 0; --i) { + final TaskStack stack = stacks.get(i); + if (stack.isVisibleLocked() && stack.isAdjustedForIme()) { + stack.beginImeAdjustAnimation(); + } + } + + // We put all tasks into drag resizing mode - wait until all of them have completed the + // drag resizing switch. + if (!mService.mWaitingForDrawn.isEmpty()) { + mService.mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT); + mService.mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT, + IME_ADJUST_DRAWN_TIMEOUT); + mAnimationStartDelayed = true; + if (imeWin != null) { + + // There might be an old window delaying the animation start - clear it. + if (mDelayedImeWin != null) { + mDelayedImeWin.mWinAnimator.endDelayingAnimationStart(); + } + mDelayedImeWin = imeWin; + imeWin.mWinAnimator.startDelayingAnimationStart(); + } + mService.mWaitingForDrawnCallback = () -> { + mAnimationStartDelayed = false; + if (mDelayedImeWin != null) { + mDelayedImeWin.mWinAnimator.endDelayingAnimationStart(); + } + notifyAdjustedForImeChanged(adjusted, IME_ADJUST_ANIM_DURATION); + }; + } else { + notifyAdjustedForImeChanged(adjusted, IME_ADJUST_ANIM_DURATION); + } + } + private void setMinimizedDockedStack(boolean minimized) { final TaskStack stack = mDisplayContent.getDockedStackVisibleForUserLocked(); notifyDockedStackMinimizedChanged(minimized, 0); @@ -413,39 +499,48 @@ public class DockedStackDividerController implements DimLayerUser { if (mAnimatingForMinimizedDockedStack) { return animateForMinimizedDockedStack(now); } else if (mAnimatingForIme) { - return animateForIme(); + return animateForIme(now); } else { return false; } } - private boolean animateForIme() { - boolean updated = false; - boolean animating = false; - + private boolean animateForIme(long now) { + if (!mAnimationStarted || mAnimationStartDelayed) { + mAnimationStarted = true; + mAnimationStartTime = now; + mAnimationDuration = (long) + (IME_ADJUST_ANIM_DURATION * mService.getWindowAnimationScaleLocked()); + } + float t = Math.min(1f, (float) (now - mAnimationStartTime) / mAnimationDuration); + t = (mAnimationTarget == 1f ? IME_ADJUST_ENTRY_INTERPOLATOR : TOUCH_RESPONSE_INTERPOLATOR) + .getInterpolation(t); final ArrayList<TaskStack> stacks = mDisplayContent.getStacks(); + boolean updated = false; for (int i = stacks.size() - 1; i >= 0; --i) { final TaskStack stack = stacks.get(i); if (stack != null && stack.isAdjustedForIme()) { - updated |= stack.updateAdjustForIme(); - animating |= stack.isAnimatingForIme(); + if (t >= 1f && mAnimationTarget == 0f) { + stack.resetAdjustedForIme(true /* adjustBoundsNow */); + updated = true; + } else { + updated |= stack.updateAdjustForIme(getInterpolatedAnimationValue(t), + false /* force */); + } + if (t >= 1f) { + stack.endImeAdjustAnimation(); + } } } - if (updated) { mService.mWindowPlacerLocked.performSurfacePlacement(); } - - if (!animating) { + if (t >= 1.0f) { mAnimatingForIme = false; - for (int i = stacks.size() - 1; i >= 0; --i) { - final TaskStack stack = stacks.get(i); - if (stack != null) { - stack.clearImeGoingAway(); - } - } + return false; + } else { + return true; } - return animating; } private boolean animateForMinimizedDockedStack(long now) { @@ -478,11 +573,15 @@ public class DockedStackDividerController implements DimLayerUser { } } + private float getInterpolatedAnimationValue(float t) { + return t * mAnimationTarget + (1 - t) * mAnimationStart; + } + /** * Gets the amount how much to minimize a stack depending on the interpolated fraction t. */ private float getMinimizeAmount(TaskStack stack, float t) { - final float naturalAmount = t * mAnimationTarget + (1 - t) * mAnimationStart; + final float naturalAmount = getInterpolatedAnimationValue(t); if (isAnimationMaximizing()) { return adjustMaximizeAmount(stack, t, naturalAmount); } else { diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 7b16dbec68a5..46a8dffc02e6 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -27,6 +27,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.H.RESIZE_TASK; +import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import android.app.ActivityManager.StackId; import android.content.pm.ActivityInfo; @@ -456,6 +457,11 @@ class Task implements DimLayer.DimLayerUser { /** Bounds of the task to be used for dimming, as well as touch related tests. */ @Override public void getDimBounds(Rect out) { + final DisplayContent displayContent = mStack.getDisplayContent(); + // It doesn't matter if we in particular are part of the resize, since we couldn't have + // a DimLayer anyway if we weren't visible. + final boolean dockedResizing = displayContent != null ? + displayContent.mDividerControllerLocked.isResizing() : false; if (useCurrentBounds()) { if (inFreeformWorkspace() && getMaxVisibleBounds(out)) { return; @@ -464,8 +470,16 @@ class Task implements DimLayer.DimLayerUser { if (!mFullscreen) { // When minimizing the docked stack when going home, we don't adjust the task bounds // so we need to intersect the task bounds with the stack bounds here. - mStack.getBounds(mTmpRect); - mTmpRect.intersect(mBounds); + // + // If we are Docked Resizing with snap points, the task bounds could be smaller than the stack + // bounds and so we don't even want to use them. Even if the app should not be resized the Dim + // should keep up with the divider. + if (dockedResizing) { + mStack.getBounds(out); + } else { + mStack.getBounds(mTmpRect); + mTmpRect.intersect(mBounds); + } out.set(mTmpRect); } else { out.set(mBounds); @@ -476,7 +490,7 @@ class Task implements DimLayer.DimLayerUser { // The bounds has been adjusted to accommodate for a docked stack, but the docked stack // is not currently visible. Go ahead a represent it as fullscreen to the rest of the // system. - mStack.getDisplayContent().getLogicalDisplayRect(out); + displayContent.getLogicalDisplayRect(out); } void setDragResizing(boolean dragResizing, int dragResizeMode) { @@ -509,6 +523,22 @@ class Task implements DimLayer.DimLayerUser { return mDragResizeMode; } + /** + * Adds all of the tasks windows to {@link WindowManagerService#mWaitingForDrawn} if drag + * resizing state of the window has been changed. + */ + void addWindowsWaitingForDrawnIfResizingChanged() { + for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) { + final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows; + for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { + final WindowState win = windows.get(winNdx); + if (win.isDragResizeChanged()) { + mService.mWaitingForDrawn.add(win); + } + } + } + } + void updateDisplayInfo(final DisplayContent displayContent) { if (displayContent == null) { return; @@ -561,7 +591,16 @@ class Task implements DimLayer.DimLayerUser { // If we are not drag resizing, force recreating of a new surface so updating // the content and positioning that surface will be in sync. - if (!win.computeDragResizing()) { + // + // As we use this flag as a hint to freeze surface boundary updates, + // we'd like to only apply this to TYPE_BASE_APPLICATION, + // windows of TYPE_APPLICATION like dialogs, could appear + // to not be drag resizing while they resize, but we'd + // still like to manipulate their frame to update crop, etc... + // + // Anyway we don't need to synchronize position and content updates for these + // windows since they aren't at the base layer and could be moved around anyway. + if (!win.computeDragResizing() && win.mAttrs.type == TYPE_BASE_APPLICATION) { win.mResizedWhileNotDragResizing = true; } } @@ -619,6 +658,16 @@ class Task implements DimLayer.DimLayerUser { return false; } + boolean isVisible() { + for (int i = mAppTokens.size() - 1; i >= 0; i--) { + final AppWindowToken appToken = mAppTokens.get(i); + if (appToken.isVisible()) { + return true; + } + } + return false; + } + boolean inHomeStack() { return mStack != null && mStack.mStackId == HOME_STACK_ID; } diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index 7074a83a812f..c322cd829f1c 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -26,6 +26,7 @@ import static android.view.WindowManager.DOCKED_INVALID; import static android.view.WindowManager.DOCKED_LEFT; import static android.view.WindowManager.DOCKED_RIGHT; import static android.view.WindowManager.DOCKED_TOP; +import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.H.RESIZE_STACK; @@ -40,6 +41,7 @@ import android.util.Slog; import android.util.SparseArray; import android.view.DisplayInfo; import android.view.Surface; +import android.view.animation.PathInterpolator; import com.android.internal.policy.DividerSnapAlgorithm; import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget; @@ -52,14 +54,6 @@ import java.util.ArrayList; public class TaskStack implements DimLayer.DimLayerUser, BoundsAnimationController.AnimateBoundsUser { - // If the stack should be resized to fullscreen. - private static final boolean FULLSCREEN = true; - - // When we have a top-bottom split screen, we shift the bottom stack up to accommodate - // the IME window. The static flag below controls whether to run animation when the - // IME window goes away. - private static final boolean ANIMATE_IME_GOING_AWAY = false; - /** Unique identifier */ final int mStackId; @@ -83,6 +77,12 @@ public class TaskStack implements DimLayer.DimLayerUser, /** Stack bounds adjusted to screen content area (taking into account IM windows, etc.) */ private final Rect mAdjustedBounds = new Rect(); + /** + * Fully adjusted IME bounds. These are different from {@link #mAdjustedBounds} because they + * represent the state when the animation has ended. + */ + private final Rect mFullyAdjustedImeBounds = new Rect(); + /** Whether mBounds is fullscreen */ private boolean mFullscreen = true; @@ -118,6 +118,7 @@ public class TaskStack implements DimLayer.DimLayerUser, private boolean mImeGoingAway; private WindowState mImeWin; private float mMinimizeAmount; + private float mAdjustImeAmount; private final int mDockedStackMinimizeThickness; // If this is true, the task will be down or upscaled @@ -211,21 +212,26 @@ public class TaskStack implements DimLayer.DimLayerUser, * the normal task bounds. * * @param bounds The adjusted bounds. - * @param keepInsets Whether to keep the insets from the original bounds or to calculate new - * ones depending on the adjusted bounds. - * @return true if the adjusted bounds has changed. */ - private boolean setAdjustedBounds(Rect bounds, boolean keepInsets) { - if (mAdjustedBounds.equals(bounds)) { - return false; + private void setAdjustedBounds(Rect bounds) { + if (mAdjustedBounds.equals(bounds) && !isAnimatingForIme()) { + return; } mAdjustedBounds.set(bounds); final boolean adjusted = !mAdjustedBounds.isEmpty(); - alignTasksToAdjustedBounds(adjusted ? mAdjustedBounds : mBounds, - adjusted && keepInsets ? mBounds : null); + Rect insetBounds = null; + if (adjusted && isAdjustedForMinimizedDock()) { + insetBounds = mBounds; + } else if (adjusted && isAdjustedForIme()) { + if (mImeGoingAway) { + insetBounds = mBounds; + } else { + insetBounds = mFullyAdjustedImeBounds; + } + } + alignTasksToAdjustedBounds(adjusted ? mAdjustedBounds : mBounds, insetBounds); mDisplayContent.layoutNeeded = true; - return true; } private void alignTasksToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds) { @@ -828,17 +834,18 @@ public class TaskStack implements DimLayer.DimLayerUser, * @param imeWin The IME window. */ void setAdjustedForIme(WindowState imeWin) { - mAdjustedForIme = true; mImeWin = imeWin; mImeGoingAway = false; + if (!mAdjustedForIme) { + mAdjustedForIme = true; + mAdjustImeAmount = 0f; + updateAdjustForIme(0f, true /* force */); + } } boolean isAdjustedForIme() { return mAdjustedForIme || mImeGoingAway; } - void clearImeGoingAway() { - mImeGoingAway = false; - } boolean isAnimatingForIme() { return mImeWin != null && mImeWin.isAnimatingLw(); @@ -852,16 +859,14 @@ public class TaskStack implements DimLayer.DimLayerUser, * * @return true if a traversal should be performed after the adjustment. */ - boolean updateAdjustForIme() { - boolean stopped = false; - if (mImeGoingAway && (!ANIMATE_IME_GOING_AWAY || !isAnimatingForIme())) { - mImeWin = null; - mAdjustedForIme = false; - stopped = true; + boolean updateAdjustForIme(float adjustAmount, boolean force) { + if (adjustAmount != mAdjustImeAmount || force) { + mAdjustImeAmount = adjustAmount; + updateAdjustedBounds(); + return isVisibleForUserLocked(); + } else { + return false; } - // Make sure to run a traversal when the animation stops so that the stack - // is moved to its final position. - return updateAdjustedBounds() || stopped; } /** @@ -875,6 +880,7 @@ public class TaskStack implements DimLayer.DimLayerUser, mImeWin = null; mAdjustedForIme = false; mImeGoingAway = false; + mAdjustImeAmount = 0f; updateAdjustedBounds(); } else { mImeGoingAway |= mAdjustedForIme; @@ -901,10 +907,32 @@ public class TaskStack implements DimLayer.DimLayerUser, return mMinimizeAmount != 0f; } + /** + * Puts all visible tasks that are adjusted for IME into resizing mode and adds the windows + * to the list of to be drawn windows the service is waiting for. + */ + void beginImeAdjustAnimation() { + for (int j = mTasks.size() - 1; j >= 0; j--) { + final Task task = mTasks.get(j); + if (task.isVisibleForUser()) { + task.setDragResizing(true, DRAG_RESIZE_MODE_DOCKED_DIVIDER); + task.addWindowsWaitingForDrawnIfResizingChanged(); + } + } + } + + /** + * Resets the resizing state of all windows. + */ + void endImeAdjustAnimation() { + for (int j = mTasks.size() - 1; j >= 0; j--) { + mTasks.get(j).setDragResizing(false, DRAG_RESIZE_MODE_DOCKED_DIVIDER); + } + } + private boolean adjustForIME(final WindowState imeWin) { final int dockedSide = getDockSide(); final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM; - final Rect adjustedBounds = mTmpAdjustedBounds; if (imeWin == null || !dockedTopOrBottom) { return false; } @@ -917,41 +945,37 @@ public class TaskStack implements DimLayer.DimLayerUser, contentBounds.set(displayContentRect); int imeTop = Math.max(imeWin.getFrameLw().top, contentBounds.top); - // if IME window is animating, get its actual vertical shown position (but no smaller than - // the final target vertical position) - if (imeWin.isAnimatingLw()) { - imeTop = Math.max(imeTop, imeWin.getShownPositionLw().y); - } imeTop += imeWin.getGivenContentInsetsLw().top; if (contentBounds.bottom > imeTop) { contentBounds.bottom = imeTop; } - // If content bounds not changing, nothing to do. - if (mLastContentBounds.equals(contentBounds)) { - return true; - } - - // Content bounds changed, need to apply adjustments depending on dock sides. mLastContentBounds.set(contentBounds); - adjustedBounds.set(mBounds); final int yOffset = displayContentRect.bottom - contentBounds.bottom; if (dockedSide == DOCKED_TOP) { // If this stack is docked on top, we make it smaller so the bottom stack is not // occluded by IME. We shift its bottom up by the height of the IME (capped by // the display content rect). Note that we don't change the task bounds. - adjustedBounds.bottom = Math.max( - adjustedBounds.bottom - yOffset, displayContentRect.top); + int bottom = Math.max( + mBounds.bottom - yOffset, displayContentRect.top); + mTmpAdjustedBounds.set(mBounds); + mTmpAdjustedBounds.bottom = + (int) (mAdjustImeAmount * bottom + (1 - mAdjustImeAmount) * mBounds.bottom); + mFullyAdjustedImeBounds.set(mBounds); } else { // If this stack is docked on bottom, we shift it up so that it's not occluded by // IME. We try to move it up by the height of the IME window (although the best // we could do is to make the top stack fully collapsed). final int dividerWidth = getDisplayContent().mDividerControllerLocked .getContentWidth(); - adjustedBounds.top = Math.max( - adjustedBounds.top - yOffset, displayContentRect.top + dividerWidth); - adjustedBounds.bottom = adjustedBounds.top + mBounds.height(); + int top = Math.max(mBounds.top - yOffset, displayContentRect.top + dividerWidth); + mTmpAdjustedBounds.set(mBounds); + mTmpAdjustedBounds.top = + (int) (mAdjustImeAmount * top + (1 - mAdjustImeAmount) * mBounds.top); + mFullyAdjustedImeBounds.set(mBounds); + mFullyAdjustedImeBounds.top = top; + mFullyAdjustedImeBounds.bottom = top + mBounds.height(); } return true; } @@ -1007,7 +1031,7 @@ public class TaskStack implements DimLayer.DimLayerUser, /** * Updates the adjustment depending on it's current state. */ - boolean updateAdjustedBounds() { + void updateAdjustedBounds() { boolean adjust = false; if (mMinimizeAmount != 0f) { adjust = adjustForMinimizedDockedStack(mMinimizeAmount); @@ -1018,7 +1042,7 @@ public class TaskStack implements DimLayer.DimLayerUser, mTmpAdjustedBounds.setEmpty(); mLastContentBounds.setEmpty(); } - return setAdjustedBounds(mTmpAdjustedBounds, isAdjustedForMinimizedDockedStack()); + setAdjustedBounds(mTmpAdjustedBounds); } boolean isAdjustedForMinimizedDockedStack() { @@ -1030,6 +1054,9 @@ public class TaskStack implements DimLayer.DimLayerUser, pw.println(prefix + "mDeferDetach=" + mDeferDetach); pw.println(prefix + "mFullscreen=" + mFullscreen); pw.println(prefix + "mBounds=" + mBounds.toShortString()); + if (!mAdjustedBounds.isEmpty()) { + pw.println(prefix + "mAdjustedBounds=" + mAdjustedBounds.toShortString()); + } for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; taskNdx--) { mTasks.get(taskNdx).dump(prefix + " ", pw); } @@ -1158,7 +1185,7 @@ public class TaskStack implements DimLayer.DimLayerUser, return mDragResizing; } - private void setDragResizingLocked(boolean resizing) { + void setDragResizingLocked(boolean resizing) { if (mDragResizing == resizing) { return; } diff --git a/services/core/java/com/android/server/wm/WindowLayersController.java b/services/core/java/com/android/server/wm/WindowLayersController.java index 6bdcd42ee081..0217c094ba83 100644 --- a/services/core/java/com/android/server/wm/WindowLayersController.java +++ b/services/core/java/com/android/server/wm/WindowLayersController.java @@ -218,7 +218,7 @@ public class WindowLayersController { } private int assignAndIncreaseLayerIfNeeded(WindowState win, int layer) { - if (win != null && layer > win.mLayer) { + if (win != null) { assignAnimLayer(win, layer); // Make sure we leave space inbetween normal windows for dims and such. layer += WINDOW_LAYER_MULTIPLIER; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 79abf25d4f7e..a4238c1a4017 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2602,7 +2602,7 @@ public class WindowManagerService extends IWindowManager.Stub void repositionChild(Session session, IWindow client, int left, int top, int right, int bottom, - long deferTransactionUntilFrame, Rect outFrame) { + long frameNumber, Rect outFrame) { Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "repositionChild"); long origId = Binder.clearCallingIdentity(); @@ -2638,10 +2638,8 @@ public class WindowManagerService extends IWindowManager.Stub win.mWinAnimator.setSurfaceBoundariesLocked(false); - if (deferTransactionUntilFrame > 0) { - win.mWinAnimator.mSurfaceController.deferTransactionUntil( - win.mAttachedWindow.mWinAnimator.mSurfaceController.getHandle(), - deferTransactionUntilFrame); + if (frameNumber > 0) { + win.mWinAnimator.deferTransactionUntilParentFrame(frameNumber); } } finally { @@ -7445,7 +7443,7 @@ public class WindowManagerService extends IWindowManager.Stub } } - private void adjustForImeIfNeeded(final DisplayContent displayContent) { + void adjustForImeIfNeeded(final DisplayContent displayContent) { final WindowState imeWin = mInputMethodWindow; final TaskStack focusedStack = mCurrentFocus != null ? mCurrentFocus.getStack() : null; @@ -7461,14 +7459,14 @@ public class WindowManagerService extends IWindowManager.Stub stack.setAdjustedForIme(imeWin); } } - displayContent.mDividerControllerLocked.setAdjustedForIme(true, true); + displayContent.mDividerControllerLocked.setAdjustedForIme(true, true, imeWin); } else { final ArrayList<TaskStack> stacks = displayContent.getStacks(); for (int i = stacks.size() - 1; i >= 0; --i) { final TaskStack stack = stacks.get(i); stack.resetAdjustedForIme(!dockVisible); } - displayContent.mDividerControllerLocked.setAdjustedForIme(false, dockVisible); + displayContent.mDividerControllerLocked.setAdjustedForIme(false, dockVisible, imeWin); } } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 8371cfe7a2dd..bf697172f609 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -82,6 +82,7 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; @@ -444,6 +445,11 @@ final class WindowState implements WindowManagerPolicy.WindowState { // If not null, the window that will be used to replace the old one. This is being set when // the window is added and unset when this window reports its first draw. WindowState mReplacingWindow = null; + // For the new window in the replacement transition, if we have + // requested to replace without animation, then we should + // make sure we also don't apply an enter animation for + // the new window. + boolean mSkipEnterAnimationForSeamlessReplacement = false; // Whether this window is being moved via the resize API boolean mMovedByResize; @@ -1552,7 +1558,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { // If app died visible, apply a dim over the window to indicate that it's inactive mDisplayContent.mDimLayerController.applyDimAbove(getDimLayerUser(), mWinAnimator); } else if ((mAttrs.flags & FLAG_DIM_BEHIND) != 0 - && mDisplayContent != null && !mAnimatingExit && isDisplayedLw()) { + && mDisplayContent != null && !mAnimatingExit && isVisibleUnchecked()) { mDisplayContent.mDimLayerController.applyDimBehind(getDimLayerUser(), mWinAnimator); } } @@ -1571,12 +1577,16 @@ final class WindowState implements WindowManagerPolicy.WindowState { } for (int i = mAppToken.allAppWindows.size() - 1; i >= 0; i--) { final WindowState win = mAppToken.allAppWindows.get(i); - if (win.mWillReplaceWindow && win.mReplacingWindow == this) { + if (win.mWillReplaceWindow && win.mReplacingWindow == this && hasDrawnLw()) { if (DEBUG_ADD_REMOVE) Slog.d(TAG, "Removing replaced window: " + win); + if (win.isDimming()) { + win.transferDimToReplacement(); + } win.mWillReplaceWindow = false; win.mAnimateReplacingWindow = false; win.mReplacingRemoveRequested = false; win.mReplacingWindow = null; + mSkipEnterAnimationForSeamlessReplacement = false; if (win.mAnimatingExit) { mService.removeWindowInnerLocked(win); } @@ -2710,4 +2720,25 @@ final class WindowState implements WindowManagerPolicy.WindowState { } return winY; } + + void transferDimToReplacement() { + final DimLayer.DimLayerUser dimLayerUser = getDimLayerUser(); + if (dimLayerUser != null && mDisplayContent != null) { + mDisplayContent.mDimLayerController.applyDim(dimLayerUser, + mReplacingWindow.mWinAnimator, + (mAttrs.flags & FLAG_DIM_BEHIND) != 0 ? true : false); + } + } + + // During activity relaunch due to resize, we sometimes use window replacement + // for only child windows (as the main window is handled by window preservation) + // and the big surface. + // + // Though windows of TYPE_APPLICATION (as opposed to TYPE_BASE_APPLICATION) + // are not children in the sense of an attached window, we also want to replace + // them at such phases, as they won't be covered by window preservation, + // and in general we expect them to return following relaunch. + boolean shouldBeReplacedWithChildren() { + return isChildWindow() || mAttrs.type == TYPE_APPLICATION; + } } diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 024551340166..1f76f318b251 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -21,7 +21,8 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; import static android.view.WindowManager.LayoutParams.FLAG_SCALED; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; -import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER; +import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; +import static com.android.server.wm.AppWindowAnimator.sDummyAnimation; import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; @@ -182,6 +183,8 @@ class WindowStateAnimator { * window is first added or shown, cleared when the callback has been made. */ boolean mEnteringAnimation; + private boolean mAnimationStartDelayed; + boolean mKeyguardGoingAwayAnimation; boolean mKeyguardGoingAwayWithWallpaper; @@ -220,6 +223,10 @@ class WindowStateAnimator { int mAttrType; + static final long PENDING_TRANSACTION_FINISH_WAIT_TIME = 100; + long mDeferTransactionUntilFrame = -1; + long mDeferTransactionTime = -1; + private final Rect mTmpSize = new Rect(); WindowStateAnimator(final WindowState win) { @@ -294,7 +301,7 @@ class WindowStateAnimator { /** Is the window animating the DummyAnimation? */ boolean isDummyAnimation() { return mAppAnimator != null - && mAppAnimator.animation == AppWindowAnimator.sDummyAnimation; + && mAppAnimator.animation == sDummyAnimation; } /** Is this window currently set to animate or currently animating? */ @@ -318,8 +325,12 @@ class WindowStateAnimator { if ((mAnimation == null) || !mLocalAnimating) { return false; } + currentTime = getAnimationFrameTime(mAnimation, currentTime); mTransformation.clear(); final boolean more = mAnimation.getTransformation(currentTime, mTransformation); + if (mAnimationStartDelayed && mAnimationIsEntrance) { + mTransformation.setAlpha(0f); + } if (false && DEBUG_ANIM) Slog.v(TAG, "Stepped animation in " + this + ": more=" + more + ", xform=" + mTransformation); return more; @@ -1673,6 +1684,12 @@ class WindowStateAnimator { } void applyEnterAnimationLocked() { + // If we are the new part of a window replacement transition and we have requested + // not to animate, we instead want to make it seamless, so we don't want to apply + // an enter transition. + if (mWin.mSkipEnterAnimationForSeamlessReplacement) { + return; + } final int transit; if (mEnterAnimationPending) { mEnterAnimationPending = false; @@ -1755,7 +1772,13 @@ class WindowStateAnimator { } else { clearAnimation(); } - + if (mWin.mAttrs.type == TYPE_INPUT_METHOD) { + mService.adjustForImeIfNeeded(mWin.mDisplayContent); + if (isEntrance) { + mWin.setDisplayLayoutNeeded(); + mService.mWindowPlacerLocked.requestTraversal(); + } + } return mAnimation != null; } @@ -1834,6 +1857,9 @@ class WindowStateAnimator { pw.print(" mDsDy="); pw.print(mDsDy); pw.print(" mDtDy="); pw.println(mDtDy); } + if (mAnimationStartDelayed) { + pw.print(prefix); pw.print("mAnimationStartDelayed="); pw.print(mAnimationStartDelayed); + } } @Override @@ -1880,4 +1906,57 @@ class WindowStateAnimator { mAnimDy = mWin.mLastFrame.top - top; mAnimateMove = true; } + + void deferTransactionUntilParentFrame(long frameNumber) { + if (!mWin.isChildWindow()) { + return; + } + mDeferTransactionUntilFrame = frameNumber; + mDeferTransactionTime = System.currentTimeMillis(); + mSurfaceController.deferTransactionUntil( + mWin.mAttachedWindow.mWinAnimator.mSurfaceController.getHandle(), + frameNumber); + } + + // Defer the current transaction to the frame number of the last saved transaction. + // We do this to avoid shooting through an unsynchronized transaction while something is + // pending. This is generally fine, as either we will get in on the synchronization, + // or SurfaceFlinger will see that the frame has already occured. The only + // potential problem is in frame number resets so we reset things with a timeout + // every so often to be careful. + void deferToPendingTransaction() { + if (mDeferTransactionUntilFrame < 0) { + return; + } + long time = System.currentTimeMillis(); + if (time > mDeferTransactionTime + PENDING_TRANSACTION_FINISH_WAIT_TIME) { + mDeferTransactionTime = -1; + mDeferTransactionUntilFrame = -1; + } else { + mSurfaceController.deferTransactionUntil( + mWin.mAttachedWindow.mWinAnimator.mSurfaceController.getHandle(), + mDeferTransactionUntilFrame); + } + } + + /** + * Sometimes we need to synchronize the first frame of animation with some external event. + * To achieve this, we prolong the start of the animation and keep producing the first frame of + * the animation. + */ + private long getAnimationFrameTime(Animation animation, long currentTime) { + if (mAnimationStartDelayed) { + animation.setStartTime(currentTime); + return currentTime + 1; + } + return currentTime; + } + + void startDelayingAnimationStart() { + mAnimationStartDelayed = true; + } + + void endDelayingAnimationStart() { + mAnimationStartDelayed = false; + } } diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java index 04aa735bc99d..1e6c585da12d 100644 --- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java +++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java @@ -721,6 +721,10 @@ class WindowSurfacePlacer { // Moved from updateWindowsAndWallpaperLocked(). if (w.mHasSurface) { + // If we have recently synchronized a previous transaction for this + // window ensure we don't push through an unsynchronized one now. + winAnimator.deferToPendingTransaction(); + // Take care of the window being ready to display. final boolean committed = winAnimator.commitFinishDrawingLocked(); if (isDefaultDisplay && committed) { diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java index ce02a79005ba..d20d5fa7f3b9 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java @@ -15,9 +15,36 @@ */ package com.android.server.pm; +import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllDynamic; +import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllDynamicOrPinned; +import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllHaveIcon; +import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllHaveIconFile; +import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllHaveIconResId; +import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllHaveIntents; +import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllHaveTitle; +import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllKeyFieldsOnly; +import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllNotHaveIntents; +import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllNotHaveTitle; +import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllNotKeyFieldsOnly; +import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllPinned; +import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllUnique; +import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertBitmapSize; +import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertBundleEmpty; +import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertCallbackNotReceived; +import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertCallbackReceived; +import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertDynamicAndPinned; +import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertDynamicOnly; +import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertExpectException; +import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertShortcutIds; +import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.hashSet; +import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list; +import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.makeBundle; +import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.pfdToBitmap; +import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.resetAll; +import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.set; + import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyList; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; @@ -27,7 +54,6 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.*; import android.annotation.NonNull; import android.annotation.Nullable; @@ -57,13 +83,11 @@ import android.graphics.Bitmap.CompressFormat; import android.graphics.BitmapFactory; import android.graphics.drawable.Icon; import android.net.Uri; -import android.os.BaseBundle; import android.os.Bundle; import android.os.FileUtils; import android.os.Handler; import android.os.Looper; import android.os.Parcel; -import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; import android.os.Process; import android.os.UserHandle; @@ -71,7 +95,6 @@ import android.os.UserManager; import android.test.InstrumentationTestCase; import android.test.mock.MockContext; import android.test.suitebuilder.annotation.SmallTest; -import android.util.ArraySet; import android.util.Log; import android.util.Pair; import android.util.SparseArray; @@ -84,9 +107,6 @@ import com.android.server.pm.LauncherAppsService.LauncherAppsImpl; import com.android.server.pm.ShortcutService.ConfigConstants; import com.android.server.pm.ShortcutService.FileOutputStreamWithPath; import com.android.server.pm.ShortcutUser.PackageWithUser; -import com.android.server.testutis.TestUtils; - -import libcore.io.IoUtils; import org.junit.Assert; import org.mockito.ArgumentCaptor; @@ -98,8 +118,6 @@ import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -4018,24 +4036,33 @@ public class ShortcutManagerTest extends InstrumentationTestCase { checkCanRestoreTo(false, spi2, 11, "x", "sig2x", "sig1", "y"); } + private boolean bitmapDirectoryExists(String packageName, int userId) { + final File path = new File(mService.getUserBitmapFilePath(userId), packageName); + return path.isDirectory(); + } + public void testHandlePackageDelete() { + final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource( + getTestContext().getResources(), R.drawable.black_32x32)); setCaller(CALLING_PACKAGE_1, USER_0); - assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1")))); + assertTrue(mManager.addDynamicShortcuts(list( + makeShortcutWithIcon("s1", bmp32x32), makeShortcutWithIcon("s2", bmp32x32) + ))); setCaller(CALLING_PACKAGE_2, USER_0); - assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1")))); + assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32)))); setCaller(CALLING_PACKAGE_3, USER_0); - assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1")))); + assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32)))); setCaller(CALLING_PACKAGE_1, USER_10); - assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1")))); + assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32)))); setCaller(CALLING_PACKAGE_2, USER_10); - assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1")))); + assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32)))); setCaller(CALLING_PACKAGE_3, USER_10); - assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1")))); + assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32)))); assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0)); assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0)); @@ -4044,6 +4071,13 @@ public class ShortcutManagerTest extends InstrumentationTestCase { assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10)); assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10)); + uninstallPackage(USER_0, CALLING_PACKAGE_1); mService.mPackageMonitor.onReceive(getTestContext(), genPackageDeleteIntent(CALLING_PACKAGE_1, USER_0)); @@ -4055,6 +4089,13 @@ public class ShortcutManagerTest extends InstrumentationTestCase { assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10)); assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10)); + assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10)); + uninstallPackage(USER_10, CALLING_PACKAGE_2); mService.mPackageMonitor.onReceive(getTestContext(), genPackageDeleteIntent(CALLING_PACKAGE_2, USER_10)); @@ -4066,6 +4107,13 @@ public class ShortcutManagerTest extends InstrumentationTestCase { assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10)); assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10)); + assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10)); + assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10)); + mInjectedPackages.remove(CALLING_PACKAGE_1); mInjectedPackages.remove(CALLING_PACKAGE_3); @@ -4078,6 +4126,13 @@ public class ShortcutManagerTest extends InstrumentationTestCase { assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10)); assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10)); + assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0)); + assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10)); + assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10)); + mService.handleUnlockUser(USER_10); assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0)); @@ -4086,6 +4141,13 @@ public class ShortcutManagerTest extends InstrumentationTestCase { assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10)); assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10)); assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10)); + + assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0)); + assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0)); + assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0)); + assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10)); + assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10)); + assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10)); } private void backupAndRestore() { diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java index 87fc7fa367d2..2579d9f81b26 100644 --- a/wifi/java/android/net/wifi/RttManager.java +++ b/wifi/java/android/net/wifi/RttManager.java @@ -199,6 +199,12 @@ public class RttManager { // Whether STA responder role is supported. public boolean responderSupported; + /** Whether the secure RTT protocol is supported. */ + public boolean secureRttSupported; + + /** Draft 11mc version supported, including major and minor version. e.g, draft 4.3 is 43 */ + public int mcVersion; + @Override public String toString() { StringBuffer sb = new StringBuffer(); @@ -223,7 +229,7 @@ public class RttManager { sb.append("VHT "); } - sb.append("is supported. \n"); + sb.append("is supported. "); if ((bwSupported & RTT_BW_5_SUPPORT) != 0) { sb.append("5 MHz "); @@ -252,7 +258,10 @@ public class RttManager { sb.append("is supported."); sb.append(" STA responder role is ") - .append(responderSupported ? "supported" : "not supported."); + .append(responderSupported ? "supported" : "not supported"); + sb.append(" Secure RTT protocol is ") + .append(secureRttSupported ? "supported" : "not supported"); + sb.append(" 11mc version is " + mcVersion); return sb.toString(); } @@ -272,6 +281,8 @@ public class RttManager { dest.writeInt(preambleSupported); dest.writeInt(bwSupported); dest.writeInt(responderSupported ? 1 : 0); + dest.writeInt(secureRttSupported ? 1 : 0); + dest.writeInt(mcVersion); } /** Implement the Parcelable interface {@hide} */ @@ -279,16 +290,18 @@ public class RttManager { new Creator<RttCapabilities>() { @Override public RttCapabilities createFromParcel(Parcel in) { - RttCapabilities capabilities = new RttCapabilities(); - capabilities.oneSidedRttSupported = (in.readInt() == 1); - capabilities.twoSided11McRttSupported = (in.readInt() == 1); - capabilities.lciSupported = (in.readInt() == 1); - capabilities.lcrSupported = (in.readInt() == 1); - capabilities.preambleSupported = in.readInt(); - capabilities.bwSupported = in.readInt(); - capabilities.responderSupported = (in.readInt() == 1); - return capabilities; - } + RttCapabilities capabilities = new RttCapabilities(); + capabilities.oneSidedRttSupported = (in.readInt() == 1); + capabilities.twoSided11McRttSupported = (in.readInt() == 1); + capabilities.lciSupported = (in.readInt() == 1); + capabilities.lcrSupported = (in.readInt() == 1); + capabilities.preambleSupported = in.readInt(); + capabilities.bwSupported = in.readInt(); + capabilities.responderSupported = (in.readInt() == 1); + capabilities.secureRttSupported = (in.readInt() == 1); + capabilities.mcVersion = in.readInt(); + return capabilities; + } /** Implement the Parcelable interface {@hide} */ @Override public RttCapabilities[] newArray(int size) { diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java index 1a8197c85dbd..2ee1aefc559e 100644 --- a/wifi/java/android/net/wifi/WifiScanner.java +++ b/wifi/java/android/net/wifi/WifiScanner.java @@ -20,7 +20,6 @@ import android.annotation.SystemApi; import android.content.Context; import android.os.Bundle; import android.os.Handler; -import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.os.Messenger; @@ -31,13 +30,11 @@ import android.os.WorkSource; import android.util.Log; import android.util.SparseArray; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.AsyncChannel; import com.android.internal.util.Preconditions; import com.android.internal.util.Protocol; import java.util.List; -import java.util.concurrent.CountDownLatch; /** @@ -1143,7 +1140,6 @@ public class WifiScanner { private final Object mListenerMapLock = new Object(); private AsyncChannel mAsyncChannel; - private final CountDownLatch mConnected; private final Handler mInternalHandler; /** @@ -1157,22 +1153,6 @@ public class WifiScanner { * @hide */ public WifiScanner(Context context, IWifiScanner service, Looper looper) { - this(context, service, looper, true); - } - - /** - * Create a new WifiScanner instance. - * - * @param context The application context. - * @param service The IWifiScanner Binder interface - * @param looper the Looper used to deliver callbacks - * @param waitForConnection If true, this will not return until a connection to Wifi Scanner - * service is established. - * @hide - */ - @VisibleForTesting - public WifiScanner(Context context, IWifiScanner service, Looper looper, - boolean waitForConnection) { mContext = context; mService = service; @@ -1188,17 +1168,12 @@ public class WifiScanner { } mAsyncChannel = new AsyncChannel(); - mConnected = new CountDownLatch(1); mInternalHandler = new ServiceHandler(looper); - mAsyncChannel.connect(mContext, mInternalHandler, messenger); - if (waitForConnection) { - try { - mConnected.await(); - } catch (InterruptedException e) { - Log.e(TAG, "interrupted wait at init"); - } - } + mAsyncChannel.connectSync(mContext, mInternalHandler, messenger); + // We cannot use fullyConnectSync because it sends the FULL_CONNECTION message + // synchronously, which causes WifiScanningService to receive the wrong replyTo value. + mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); } private void validateChannel() { @@ -1326,17 +1301,6 @@ public class WifiScanner { @Override public void handleMessage(Message msg) { switch (msg.what) { - case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: - if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { - mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); - } else { - Log.e(TAG, "Failed to set up channel connection"); - // This will cause all further async API calls on the WifiManager - // to fail and throw an exception - mAsyncChannel = null; - } - mConnected.countDown(); - return; case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED: return; case AsyncChannel.CMD_CHANNEL_DISCONNECTED: |