diff options
115 files changed, 1824 insertions, 1071 deletions
diff --git a/Android.mk b/Android.mk index 28adbcaf88fc..7a8b1b763b4c 100644 --- a/Android.mk +++ b/Android.mk @@ -295,9 +295,9 @@ LOCAL_SRC_FILES += \ core/java/android/printservice/IPrintService.aidl \ core/java/android/printservice/IPrintServiceClient.aidl \ core/java/android/companion/ICompanionDeviceManager.aidl \ - core/java/android/companion/ICompanionDeviceManagerService.aidl \ - core/java/android/companion/ICompanionDeviceManagerServiceCallback.aidl \ - core/java/android/companion/IOnAssociateCallback.aidl \ + core/java/android/companion/ICompanionDeviceDiscoveryService.aidl \ + core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl \ + core/java/android/companion/IFindDeviceCallback.aidl \ core/java/android/service/dreams/IDreamManager.aidl \ core/java/android/service/dreams/IDreamService.aidl \ core/java/android/service/persistentdata/IPersistentDataBlockService.aidl \ diff --git a/api/current.txt b/api/current.txt index b00628d1566f..7465c4d1dd88 100644 --- a/api/current.txt +++ b/api/current.txt @@ -121,6 +121,7 @@ package android { field public static final java.lang.String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES"; field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES"; field public static final java.lang.String RESTRICTED_VR_ACCESS = "android.permission.RESTRICTED_VR_ACCESS"; + field public static final java.lang.String RUN_IN_BACKGROUND = "android.permission.RUN_IN_BACKGROUND"; field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE"; field public static final java.lang.String SEND_SMS = "android.permission.SEND_SMS"; field public static final java.lang.String SET_ALARM = "com.android.alarm.permission.SET_ALARM"; @@ -139,6 +140,7 @@ package android { field public static final java.lang.String TRANSMIT_IR = "android.permission.TRANSMIT_IR"; field public static final java.lang.String UNINSTALL_SHORTCUT = "com.android.launcher.permission.UNINSTALL_SHORTCUT"; field public static final java.lang.String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS"; + field public static final java.lang.String USE_DATA_IN_BACKGROUND = "android.permission.USE_DATA_IN_BACKGROUND"; field public static final java.lang.String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT"; field public static final java.lang.String USE_SIP = "android.permission.USE_SIP"; field public static final java.lang.String VIBRATE = "android.permission.VIBRATE"; @@ -6200,6 +6202,7 @@ package android.app.admin { method public void clearDeviceOwnerApp(java.lang.String); method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String); method public void clearProfileOwner(android.content.ComponentName); + method public boolean clearResetPasswordToken(android.content.ComponentName); method public void clearUserRestriction(android.content.ComponentName, java.lang.String); method public android.content.Intent createAdminSupportIntent(java.lang.String); method public android.os.UserHandle createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int); @@ -6276,6 +6279,7 @@ package android.app.admin { method public boolean isPackageSuspended(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; method public boolean isProfileOwnerApp(java.lang.String); method public boolean isProvisioningAllowed(java.lang.String); + method public boolean isResetPasswordTokenActive(android.content.ComponentName); method public boolean isSecurityLoggingEnabled(android.content.ComponentName); method public boolean isUninstallBlocked(android.content.ComponentName, java.lang.String); method public void lockNow(); @@ -6287,6 +6291,7 @@ package android.app.admin { method public boolean removeUser(android.content.ComponentName, android.os.UserHandle); method public boolean requestBugreport(android.content.ComponentName); method public boolean resetPassword(java.lang.String, int); + method public boolean resetPasswordWithToken(android.content.ComponentName, java.lang.String, byte[], int); method public java.util.List<android.app.admin.NetworkEvent> retrieveNetworkLogs(android.content.ComponentName, long); method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrievePreRebootSecurityLogs(android.content.ComponentName); method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrieveSecurityLogs(android.content.ComponentName); @@ -6335,6 +6340,7 @@ package android.app.admin { method public void setProfileName(android.content.ComponentName, java.lang.String); method public void setRecommendedGlobalProxy(android.content.ComponentName, android.net.ProxyInfo); method public void setRequiredStrongAuthTimeout(android.content.ComponentName, long); + method public boolean setResetPasswordToken(android.content.ComponentName, byte[]); method public void setRestrictionsProvider(android.content.ComponentName, android.content.ComponentName); method public void setScreenCaptureDisabled(android.content.ComponentName, boolean); method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String); @@ -9221,7 +9227,7 @@ package android.content { field public static final java.lang.String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER"; field public static final java.lang.String EXTRA_PROCESS_TEXT = "android.intent.extra.PROCESS_TEXT"; field public static final java.lang.String EXTRA_PROCESS_TEXT_READONLY = "android.intent.extra.PROCESS_TEXT_READONLY"; - field public static final java.lang.String EXTRA_QUICK_VIEW_PLAIN = "android.intent.extra.QUICK_VIEW_PLAIN"; + field public static final java.lang.String EXTRA_QUICK_VIEW_ADVANCED = "android.intent.extra.QUICK_VIEW_ADVANCED"; field public static final java.lang.String EXTRA_QUIET_MODE = "android.intent.extra.QUIET_MODE"; field public static final java.lang.String EXTRA_REFERRER = "android.intent.extra.REFERRER"; field public static final java.lang.String EXTRA_REFERRER_NAME = "android.intent.extra.REFERRER_NAME"; @@ -22317,7 +22323,7 @@ package android.media { method public void pause() throws java.lang.IllegalStateException; method public void prepare() throws java.io.IOException, java.lang.IllegalStateException; method public void prepareAsync() throws java.lang.IllegalStateException; - method public void prepareDrm(java.util.UUID, android.media.MediaPlayer.OnDrmConfigCallback) throws android.media.MediaPlayer.ProvisioningErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException; + method public void prepareDrm(java.util.UUID) throws android.media.MediaPlayer.ProvisioningErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException; method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException; method public void release(); method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException; @@ -22345,6 +22351,7 @@ package android.media { method public void setNextMediaPlayer(android.media.MediaPlayer); method public void setOnBufferingUpdateListener(android.media.MediaPlayer.OnBufferingUpdateListener); method public void setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener); + method public void setOnDrmConfigListener(android.media.MediaPlayer.OnDrmConfigListener); method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener); method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener, android.os.Handler); method public void setOnDrmPreparedListener(android.media.MediaPlayer.OnDrmPreparedListener); @@ -22409,9 +22416,8 @@ package android.media { method public abstract void onCompletion(android.media.MediaPlayer); } - public static abstract class MediaPlayer.OnDrmConfigCallback { - ctor public MediaPlayer.OnDrmConfigCallback(); - method public void onDrmConfig(android.media.MediaPlayer); + public static abstract interface MediaPlayer.OnDrmConfigListener { + method public abstract void onDrmConfig(android.media.MediaPlayer); } public static abstract interface MediaPlayer.OnDrmInfoListener { @@ -44108,6 +44114,7 @@ package android.view { field public static final int AXIS_RX = 12; // 0xc field public static final int AXIS_RY = 13; // 0xd field public static final int AXIS_RZ = 14; // 0xe + field public static final int AXIS_SCROLL = 26; // 0x1a field public static final int AXIS_SIZE = 3; // 0x3 field public static final int AXIS_THROTTLE = 19; // 0x13 field public static final int AXIS_TILT = 25; // 0x19 @@ -47335,7 +47342,7 @@ package android.view.textclassifier { public final class TextClassificationManager { method public java.util.List<android.view.textclassifier.TextLanguage> detectLanguages(java.lang.CharSequence); - method public synchronized android.view.textclassifier.TextClassifier getDefaultTextClassifier(); + method public android.view.textclassifier.TextClassifier getDefaultTextClassifier(); } public final class TextClassificationResult { diff --git a/api/system-current.txt b/api/system-current.txt index 2a3327ee16cc..25b393c8e27c 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -211,6 +211,7 @@ package android { field public static final java.lang.String RESTRICTED_VR_ACCESS = "android.permission.RESTRICTED_VR_ACCESS"; field public static final java.lang.String RETRIEVE_WINDOW_CONTENT = "android.permission.RETRIEVE_WINDOW_CONTENT"; field public static final java.lang.String REVOKE_RUNTIME_PERMISSIONS = "android.permission.REVOKE_RUNTIME_PERMISSIONS"; + field public static final java.lang.String RUN_IN_BACKGROUND = "android.permission.RUN_IN_BACKGROUND"; field public static final java.lang.String SCORE_NETWORKS = "android.permission.SCORE_NETWORKS"; field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE"; field public static final java.lang.String SEND_SMS = "android.permission.SEND_SMS"; @@ -248,6 +249,7 @@ package android { field public static final java.lang.String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS"; field public static final java.lang.String UPDATE_LOCK = "android.permission.UPDATE_LOCK"; field public static final java.lang.String USER_ACTIVITY = "android.permission.USER_ACTIVITY"; + field public static final java.lang.String USE_DATA_IN_BACKGROUND = "android.permission.USE_DATA_IN_BACKGROUND"; field public static final java.lang.String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT"; field public static final java.lang.String USE_SIP = "android.permission.USE_SIP"; field public static final java.lang.String VIBRATE = "android.permission.VIBRATE"; @@ -6405,6 +6407,7 @@ package android.app.admin { method public void clearDeviceOwnerApp(java.lang.String); method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String); method public void clearProfileOwner(android.content.ComponentName); + method public boolean clearResetPasswordToken(android.content.ComponentName); method public void clearUserRestriction(android.content.ComponentName, java.lang.String); method public android.content.Intent createAdminSupportIntent(java.lang.String); method public android.os.UserHandle createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int); @@ -6495,6 +6498,7 @@ package android.app.admin { method public boolean isPackageSuspended(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; method public boolean isProfileOwnerApp(java.lang.String); method public boolean isProvisioningAllowed(java.lang.String); + method public boolean isResetPasswordTokenActive(android.content.ComponentName); method public boolean isSecurityLoggingEnabled(android.content.ComponentName); method public boolean isUninstallBlocked(android.content.ComponentName, java.lang.String); method public void lockNow(); @@ -6509,6 +6513,7 @@ package android.app.admin { method public boolean removeUser(android.content.ComponentName, android.os.UserHandle); method public boolean requestBugreport(android.content.ComponentName); method public boolean resetPassword(java.lang.String, int); + method public boolean resetPasswordWithToken(android.content.ComponentName, java.lang.String, byte[], int); method public java.util.List<android.app.admin.NetworkEvent> retrieveNetworkLogs(android.content.ComponentName, long); method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrievePreRebootSecurityLogs(android.content.ComponentName); method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrieveSecurityLogs(android.content.ComponentName); @@ -6559,6 +6564,7 @@ package android.app.admin { method public void setProfileName(android.content.ComponentName, java.lang.String); method public void setRecommendedGlobalProxy(android.content.ComponentName, android.net.ProxyInfo); method public void setRequiredStrongAuthTimeout(android.content.ComponentName, long); + method public boolean setResetPasswordToken(android.content.ComponentName, byte[]); method public void setRestrictionsProvider(android.content.ComponentName, android.content.ComponentName); method public void setScreenCaptureDisabled(android.content.ComponentName, boolean); method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String); @@ -9665,7 +9671,7 @@ package android.content { field public static final java.lang.String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER"; field public static final java.lang.String EXTRA_PROCESS_TEXT = "android.intent.extra.PROCESS_TEXT"; field public static final java.lang.String EXTRA_PROCESS_TEXT_READONLY = "android.intent.extra.PROCESS_TEXT_READONLY"; - field public static final java.lang.String EXTRA_QUICK_VIEW_PLAIN = "android.intent.extra.QUICK_VIEW_PLAIN"; + field public static final java.lang.String EXTRA_QUICK_VIEW_ADVANCED = "android.intent.extra.QUICK_VIEW_ADVANCED"; field public static final java.lang.String EXTRA_QUIET_MODE = "android.intent.extra.QUIET_MODE"; field public static final java.lang.String EXTRA_REFERRER = "android.intent.extra.REFERRER"; field public static final java.lang.String EXTRA_REFERRER_NAME = "android.intent.extra.REFERRER_NAME"; @@ -23960,7 +23966,7 @@ package android.media { method public void pause() throws java.lang.IllegalStateException; method public void prepare() throws java.io.IOException, java.lang.IllegalStateException; method public void prepareAsync() throws java.lang.IllegalStateException; - method public void prepareDrm(java.util.UUID, android.media.MediaPlayer.OnDrmConfigCallback) throws android.media.MediaPlayer.ProvisioningErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException; + method public void prepareDrm(java.util.UUID) throws android.media.MediaPlayer.ProvisioningErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException; method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException; method public void release(); method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException; @@ -23988,6 +23994,7 @@ package android.media { method public void setNextMediaPlayer(android.media.MediaPlayer); method public void setOnBufferingUpdateListener(android.media.MediaPlayer.OnBufferingUpdateListener); method public void setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener); + method public void setOnDrmConfigListener(android.media.MediaPlayer.OnDrmConfigListener); method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener); method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener, android.os.Handler); method public void setOnDrmPreparedListener(android.media.MediaPlayer.OnDrmPreparedListener); @@ -24052,9 +24059,8 @@ package android.media { method public abstract void onCompletion(android.media.MediaPlayer); } - public static abstract class MediaPlayer.OnDrmConfigCallback { - ctor public MediaPlayer.OnDrmConfigCallback(); - method public void onDrmConfig(android.media.MediaPlayer); + public static abstract interface MediaPlayer.OnDrmConfigListener { + method public abstract void onDrmConfig(android.media.MediaPlayer); } public static abstract interface MediaPlayer.OnDrmInfoListener { @@ -47546,6 +47552,7 @@ package android.view { field public static final int AXIS_RX = 12; // 0xc field public static final int AXIS_RY = 13; // 0xd field public static final int AXIS_RZ = 14; // 0xe + field public static final int AXIS_SCROLL = 26; // 0x1a field public static final int AXIS_SIZE = 3; // 0x3 field public static final int AXIS_THROTTLE = 19; // 0x13 field public static final int AXIS_TILT = 25; // 0x19 @@ -50776,7 +50783,7 @@ package android.view.textclassifier { public final class TextClassificationManager { method public java.util.List<android.view.textclassifier.TextLanguage> detectLanguages(java.lang.CharSequence); - method public synchronized android.view.textclassifier.TextClassifier getDefaultTextClassifier(); + method public android.view.textclassifier.TextClassifier getDefaultTextClassifier(); } public final class TextClassificationResult { diff --git a/api/test-current.txt b/api/test-current.txt index 5bf2f6bf6dac..2c2831f9ace0 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -121,6 +121,7 @@ package android { field public static final java.lang.String REQUEST_INSTALL_PACKAGES = "android.permission.REQUEST_INSTALL_PACKAGES"; field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES"; field public static final java.lang.String RESTRICTED_VR_ACCESS = "android.permission.RESTRICTED_VR_ACCESS"; + field public static final java.lang.String RUN_IN_BACKGROUND = "android.permission.RUN_IN_BACKGROUND"; field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE"; field public static final java.lang.String SEND_SMS = "android.permission.SEND_SMS"; field public static final java.lang.String SET_ALARM = "com.android.alarm.permission.SET_ALARM"; @@ -139,6 +140,7 @@ package android { field public static final java.lang.String TRANSMIT_IR = "android.permission.TRANSMIT_IR"; field public static final java.lang.String UNINSTALL_SHORTCUT = "com.android.launcher.permission.UNINSTALL_SHORTCUT"; field public static final java.lang.String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS"; + field public static final java.lang.String USE_DATA_IN_BACKGROUND = "android.permission.USE_DATA_IN_BACKGROUND"; field public static final java.lang.String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT"; field public static final java.lang.String USE_SIP = "android.permission.USE_SIP"; field public static final java.lang.String VIBRATE = "android.permission.VIBRATE"; @@ -6217,6 +6219,7 @@ package android.app.admin { method public void clearDeviceOwnerApp(java.lang.String); method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String); method public void clearProfileOwner(android.content.ComponentName); + method public boolean clearResetPasswordToken(android.content.ComponentName); method public void clearUserRestriction(android.content.ComponentName, java.lang.String); method public android.content.Intent createAdminSupportIntent(java.lang.String); method public android.os.UserHandle createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int); @@ -6298,6 +6301,7 @@ package android.app.admin { method public boolean isPackageSuspended(android.content.ComponentName, java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; method public boolean isProfileOwnerApp(java.lang.String); method public boolean isProvisioningAllowed(java.lang.String); + method public boolean isResetPasswordTokenActive(android.content.ComponentName); method public boolean isSecurityLoggingEnabled(android.content.ComponentName); method public boolean isUninstallBlocked(android.content.ComponentName, java.lang.String); method public void lockNow(); @@ -6309,6 +6313,7 @@ package android.app.admin { method public boolean removeUser(android.content.ComponentName, android.os.UserHandle); method public boolean requestBugreport(android.content.ComponentName); method public boolean resetPassword(java.lang.String, int); + method public boolean resetPasswordWithToken(android.content.ComponentName, java.lang.String, byte[], int); method public java.util.List<android.app.admin.NetworkEvent> retrieveNetworkLogs(android.content.ComponentName, long); method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrievePreRebootSecurityLogs(android.content.ComponentName); method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrieveSecurityLogs(android.content.ComponentName); @@ -6357,6 +6362,7 @@ package android.app.admin { method public void setProfileName(android.content.ComponentName, java.lang.String); method public void setRecommendedGlobalProxy(android.content.ComponentName, android.net.ProxyInfo); method public void setRequiredStrongAuthTimeout(android.content.ComponentName, long); + method public boolean setResetPasswordToken(android.content.ComponentName, byte[]); method public void setRestrictionsProvider(android.content.ComponentName, android.content.ComponentName); method public void setScreenCaptureDisabled(android.content.ComponentName, boolean); method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String); @@ -9247,7 +9253,7 @@ package android.content { field public static final java.lang.String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER"; field public static final java.lang.String EXTRA_PROCESS_TEXT = "android.intent.extra.PROCESS_TEXT"; field public static final java.lang.String EXTRA_PROCESS_TEXT_READONLY = "android.intent.extra.PROCESS_TEXT_READONLY"; - field public static final java.lang.String EXTRA_QUICK_VIEW_PLAIN = "android.intent.extra.QUICK_VIEW_PLAIN"; + field public static final java.lang.String EXTRA_QUICK_VIEW_ADVANCED = "android.intent.extra.QUICK_VIEW_ADVANCED"; field public static final java.lang.String EXTRA_QUIET_MODE = "android.intent.extra.QUIET_MODE"; field public static final java.lang.String EXTRA_REFERRER = "android.intent.extra.REFERRER"; field public static final java.lang.String EXTRA_REFERRER_NAME = "android.intent.extra.REFERRER_NAME"; @@ -22410,7 +22416,7 @@ package android.media { method public void pause() throws java.lang.IllegalStateException; method public void prepare() throws java.io.IOException, java.lang.IllegalStateException; method public void prepareAsync() throws java.lang.IllegalStateException; - method public void prepareDrm(java.util.UUID, android.media.MediaPlayer.OnDrmConfigCallback) throws android.media.MediaPlayer.ProvisioningErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException; + method public void prepareDrm(java.util.UUID) throws android.media.MediaPlayer.ProvisioningErrorException, android.media.ResourceBusyException, android.media.UnsupportedSchemeException; method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException; method public void release(); method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException; @@ -22438,6 +22444,7 @@ package android.media { method public void setNextMediaPlayer(android.media.MediaPlayer); method public void setOnBufferingUpdateListener(android.media.MediaPlayer.OnBufferingUpdateListener); method public void setOnCompletionListener(android.media.MediaPlayer.OnCompletionListener); + method public void setOnDrmConfigListener(android.media.MediaPlayer.OnDrmConfigListener); method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener); method public void setOnDrmInfoListener(android.media.MediaPlayer.OnDrmInfoListener, android.os.Handler); method public void setOnDrmPreparedListener(android.media.MediaPlayer.OnDrmPreparedListener); @@ -22502,9 +22509,8 @@ package android.media { method public abstract void onCompletion(android.media.MediaPlayer); } - public static abstract class MediaPlayer.OnDrmConfigCallback { - ctor public MediaPlayer.OnDrmConfigCallback(); - method public void onDrmConfig(android.media.MediaPlayer); + public static abstract interface MediaPlayer.OnDrmConfigListener { + method public abstract void onDrmConfig(android.media.MediaPlayer); } public static abstract interface MediaPlayer.OnDrmInfoListener { @@ -44415,6 +44421,7 @@ package android.view { field public static final int AXIS_RX = 12; // 0xc field public static final int AXIS_RY = 13; // 0xd field public static final int AXIS_RZ = 14; // 0xe + field public static final int AXIS_SCROLL = 26; // 0x1a field public static final int AXIS_SIZE = 3; // 0x3 field public static final int AXIS_THROTTLE = 19; // 0x13 field public static final int AXIS_TILT = 25; // 0x19 @@ -47649,7 +47656,7 @@ package android.view.textclassifier { public final class TextClassificationManager { method public java.util.List<android.view.textclassifier.TextLanguage> detectLanguages(java.lang.CharSequence); - method public synchronized android.view.textclassifier.TextClassifier getDefaultTextClassifier(); + method public android.view.textclassifier.TextClassifier getDefaultTextClassifier(); } public final class TextClassificationResult { diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index 7015381dc4fb..b336472666bd 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -53,6 +53,7 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.IUserManager; import android.os.ParcelFileDescriptor; +import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.SELinux; @@ -1004,7 +1005,8 @@ public final class Pm { // In non-split user mode, userId can only be SYSTEM int parentUserId = userId >= 0 ? userId : UserHandle.USER_SYSTEM; info = mUm.createRestrictedProfile(name, parentUserId); - mAm.addSharedAccountsFromParentUser(parentUserId, userId); + mAm.addSharedAccountsFromParentUser(parentUserId, userId, + (Process.myUid() == Process.ROOT_UID) ? "root" : "com.android.shell"); } else if (userId < 0) { info = mUm.createUser(name, flags); } else { diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java index 02636819781a..7d039ef221d7 100644 --- a/core/java/android/accounts/AccountManager.java +++ b/core/java/android/accounts/AccountManager.java @@ -1802,7 +1802,7 @@ public class AccountManager { public void addSharedAccountsFromParentUser(UserHandle parentUser, UserHandle user) { try { mService.addSharedAccountsFromParentUser(parentUser.getIdentifier(), - user.getIdentifier()); + user.getIdentifier(), mContext.getOpPackageName()); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl index e0fdac146f68..49cd2c6a3953 100644 --- a/core/java/android/accounts/IAccountManager.aidl +++ b/core/java/android/accounts/IAccountManager.aidl @@ -80,7 +80,7 @@ interface IAccountManager { /* Shared accounts */ Account[] getSharedAccountsAsUser(int userId); boolean removeSharedAccountAsUser(in Account account, int userId); - void addSharedAccountsFromParentUser(int parentUserId, int userId); + void addSharedAccountsFromParentUser(int parentUserId, int userId, String opPackageName); /* Account renaming. */ void renameAccount(in IAccountManagerResponse response, in Account accountToRename, String newName); diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index fb927e96d1f5..6dd31a852172 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -357,7 +357,8 @@ public class AppOpsManager { public static final String OPSTR_INSTANT_APP_START_FOREGROUND = "android:instant_app_start_foreground"; - private static final int[] RUNTIME_PERMISSIONS_OPS = { + private static final int[] RUNTIME_AND_APPOP_PERMISSIONS_OPS = { + // RUNTIME PERMISSIONS // Contacts OP_READ_CONTACTS, OP_WRITE_CONTACTS, @@ -392,7 +393,13 @@ public class AppOpsManager { // Camera OP_CAMERA, // Body sensors - OP_BODY_SENSORS + OP_BODY_SENSORS, + + // APPOP PERMISSIONS + OP_ACCESS_NOTIFICATIONS, + OP_SYSTEM_ALERT_WINDOW, + OP_WRITE_SETTINGS, + OP_REQUEST_INSTALL_PACKAGES, }; /** @@ -926,9 +933,9 @@ public class AppOpsManager { AppOpsManager.MODE_ALLOWED, // OP_RUN_IN_BACKGROUND AppOpsManager.MODE_ALLOWED, // OP_AUDIO_ACCESSIBILITY_VOLUME AppOpsManager.MODE_ALLOWED, - AppOpsManager.MODE_DEFAULT, // OP_REQUEST_INSTALL_PACKAGES + AppOpsManager.MODE_DEFAULT, // OP_REQUEST_INSTALL_PACKAGES AppOpsManager.MODE_ALLOWED, // OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE - AppOpsManager.MODE_DEFAULT, // OP_INSTANT_APP_START_FOREGROUND + AppOpsManager.MODE_DEFAULT, // OP_INSTANT_APP_START_FOREGROUND }; /** @@ -1018,7 +1025,7 @@ public class AppOpsManager { /** * Mapping from a permission to the corresponding app op. */ - private static HashMap<String, Integer> sRuntimePermToOp = new HashMap<>(); + private static HashMap<String, Integer> sPermToOp = new HashMap<>(); static { if (sOpToSwitch.length != _NUM_OP) { @@ -1058,9 +1065,9 @@ public class AppOpsManager { sOpStrToOp.put(sOpToString[i], i); } } - for (int op : RUNTIME_PERMISSIONS_OPS) { + for (int op : RUNTIME_AND_APPOP_PERMISSIONS_OPS) { if (sOpPerms[op] != null) { - sRuntimePermToOp.put(sOpPerms[op], op); + sPermToOp.put(sOpPerms[op], op); } } } @@ -1112,12 +1119,12 @@ public class AppOpsManager { /** * Retrieve the app op code for a permission, or null if there is not one. - * This API is intended to be used for mapping runtime permissions to the - * corresponding app op. + * This API is intended to be used for mapping runtime or appop permissions + * to the corresponding app op. * @hide */ public static int permissionToOpCode(String permission) { - Integer boxedOpCode = sRuntimePermToOp.get(permission); + Integer boxedOpCode = sPermToOp.get(permission); return boxedOpCode != null ? boxedOpCode : OP_NONE; } @@ -1462,7 +1469,7 @@ public class AppOpsManager { * @return The app op associated with the permission or null. */ public static String permissionToOp(String permission) { - final Integer opCode = sRuntimePermToOp.get(permission); + final Integer opCode = sPermToOp.get(permission); if (opCode == null) { return null; } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index f1ccabe57e32..0eb47a35a47b 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -28,6 +28,7 @@ import android.annotation.UserIdInt; import android.annotation.WorkerThread; import android.app.Activity; import android.app.IServiceConnection; +import android.app.KeyguardManager; import android.app.admin.SecurityLog.SecurityEvent; import android.content.ComponentName; import android.content.Context; @@ -2694,6 +2695,11 @@ public class DevicePolicyManager { * Force a new device unlock password (the password needed to access the entire device, not for * individual accounts) on the user. This takes effect immediately. * <p> + * <em>For device owner and profile owners targeting SDK level + * {@link android.os.Build.VERSION_CODES#O} or above, this API is no longer available and will + * throw {@link SecurityException}. Please use the new API {@link #resetPasswordWithToken} + * instead. </em> + * <p> * <em>Note: This API has been limited as of {@link android.os.Build.VERSION_CODES#N} for * device admins that are not device owner and not profile owner. * The password can now only be changed if there is currently no password set. Device owner @@ -2740,6 +2746,127 @@ public class DevicePolicyManager { } /** + * Called by a profile or device owner to provision a token which can later be used to reset the + * device lockscreen password (if called by device owner), or work challenge (if called by + * profile owner), via {@link #resetPasswordWithToken}. + * <p> + * If the user currently has a lockscreen password, the provisioned token will not be + * immediately usable; it only becomes active after the user performs a confirm credential + * operation, which can be triggered by {@link KeyguardManager#createConfirmDeviceCredentialIntent}. + * If the user has no lockscreen password, the token is activated immediately. In all cases, + * the active state of the current token can be checked by {@link #isResetPasswordTokenActive}. + * For security reasons, un-activated tokens are only stored in memory and will be lost once + * the device reboots. In this case a new token needs to be provisioned again. + * <p> + * Once provisioned and activated, the token will remain effective even if the user changes + * or clears the lockscreen password. + * <p> + * <em>This token is highly sensitive and should be treated at the same level as user + * credentials. In particular, NEVER store this token on device in plaintext, especially in + * Device-Encrypted storage if the token will be used to reset password on FBE devices before + * user unlocks. + * </em> + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param token a secure token a least 32-byte long, which must be generated by a + * cryptographically strong random number generator. + * @return true if the operation is successful, false otherwise. + * @throws IllegalArgumentException if the supplied token is invalid. + * @throws SecurityException + */ + public boolean setResetPasswordToken(ComponentName admin, byte[] token) { + throwIfParentInstance("setResetPasswordToken"); + if (mService != null) { + try { + return mService.setResetPasswordToken(admin, token); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + return false; + } + + /** + * Called by a profile or device owner to revoke the current password reset token. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @return true if the operation is successful, false otherwise. + */ + public boolean clearResetPasswordToken(ComponentName admin) { + throwIfParentInstance("clearResetPasswordToken"); + if (mService != null) { + try { + return mService.clearResetPasswordToken(admin); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + return false; + } + + /** + * Called by a profile or device owner to check if the current reset password token is active. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @return true if the token is active, false otherwise. + * @throws IllegalStateException if no token has been set. + */ + public boolean isResetPasswordTokenActive(ComponentName admin) { + throwIfParentInstance("isResetPasswordTokenActive"); + if (mService != null) { + try { + return mService.isResetPasswordTokenActive(admin); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + return false; + } + + /** + * Called by device or profile owner to force set a new device unlock password or a work profile + * challenge on current user. This takes effect immediately. + * <p> + * Unlike {@link #resetPassword}, this API can change the password even before the user or + * device is unlocked or decrypted. The supplied token must have been previously provisioned via + * {@link #setResetPasswordToken}, and in active state {@link #isResetPasswordTokenActive}. + * <p> + * The given password must be sufficient for the current password quality and length constraints + * as returned by {@link #getPasswordQuality(ComponentName)} and + * {@link #getPasswordMinimumLength(ComponentName)}; if it does not meet these constraints, then + * it will be rejected and false returned. Note that the password may be a stronger quality + * (containing alphanumeric characters when the requested quality is only numeric), in which + * case the currently active quality will be increased to match. + * <p> + * Calling with a null or empty password will clear any existing PIN, pattern or password if the + * current password constraints allow it. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param password The new password for the user. Null or empty clears the password. + * @param token the password reset token previously provisioned by #setResetPasswordToken. + * @param flags May be 0 or combination of {@link #RESET_PASSWORD_REQUIRE_ENTRY} and + * {@link #RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT}. + * @return Returns true if the password was applied, or false if it is not acceptable for the + * current constraints. + * @throws SecurityException if the calling application does not own an active administrator + * that uses {@link DeviceAdminInfo#USES_POLICY_RESET_PASSWORD} + * @throws IllegalStateException if the provided token is not valid. + * @throws IllegalArgumentException if the password does not meet system requirements. + */ + public boolean resetPasswordWithToken(@NonNull ComponentName admin, String password, + byte[] token, int flags) { + throwIfParentInstance("resetPassword"); + if (mService != null) { + try { + return mService.resetPasswordWithToken(admin, password, token, flags); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + return false; + } + + /** * Called by an application that is administering the device to set the maximum time for user * activity until the device will lock. This limits the length that the user can set. It takes * effect immediately. diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 79fe10ec6158..c2f75c83da62 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -342,4 +342,9 @@ interface IDevicePolicyManager { long getLastSecurityLogRetrievalTime(); long getLastBugReportRequestTime(); long getLastNetworkLogRetrievalTime(); + + boolean setResetPasswordToken(in ComponentName admin, in byte[] token); + boolean clearResetPasswordToken(in ComponentName admin); + boolean isResetPasswordTokenActive(in ComponentName admin); + boolean resetPasswordWithToken(in ComponentName admin, String password, in byte[] token, int flags); } diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java index b379c7c57554..c0c1a4dd198b 100644 --- a/core/java/android/companion/CompanionDeviceManager.java +++ b/core/java/android/companion/CompanionDeviceManager.java @@ -29,12 +29,10 @@ import android.os.RemoteException; /** * System level service for managing companion devices * - * Usage: - * To obtain an instance call - * {@link Context#getSystemService}({@link Context#COMPANION_DEVICE_SERVICE}) - * - * Then, call {@link #associate} to initiate the flow of associating current package - * with a device selected by user + * <p>To obtain an instance call {@link Context#getSystemService}({@link + * Context#COMPANION_DEVICE_SERVICE}) Then, call {@link #associate(AssociationRequest, + * Callback, Handler)} to initiate the flow of associating current package with a + * device selected by user.</p> * * @see AssociationRequest */ @@ -47,6 +45,14 @@ public final class CompanionDeviceManager { public static final String EXTRA_DEVICE = "android.companion.extra.DEVICE"; /** + * The package name of the companion device discovery component. + * + * @hide + */ + public static final String COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME = + "com.android.companiondevicemanager"; + + /** * A callback to receive once at least one suitable device is found, or the search failed * (e.g. timed out) */ @@ -81,13 +87,20 @@ public final class CompanionDeviceManager { /** * Associate this app with a companion device, selected by user * - * Once at least one appropriate device is found, {@code callback} will be called with a + * <p>Once at least one appropriate device is found, {@code callback} will be called with a * {@link PendingIntent} that can be used to show the list of available devices for the user * to select. * It should be started for result (i.e. using * {@link android.app.Activity#startIntentSenderForResult}), as the resulting * {@link android.content.Intent} will contain extra {@link #EXTRA_DEVICE}, with the selected - * device. (e.g. {@link android.bluetooth.BluetoothDevice}) + * device. (e.g. {@link android.bluetooth.BluetoothDevice})</p> + * + * <p>If your app needs to be excluded from battery optimizations (run in the background) + * or to have unrestricted data access (use data in the background) you can declare that + * you use the {@link android.Manifest.permission#RUN_IN_BACKGROUND} and {@link + * android.Manifest.permission#USE_DATA_IN_BACKGROUND} respectively. Note that these + * special capabilities have a negative effect on the device's battery and user's data + * usage, therefore you should requested them when absolutely necessary.</p> * * @param request specific details about this request * @param callback will be called once there's at least one device found for user to choose from @@ -106,17 +119,16 @@ public final class CompanionDeviceManager { try { mService.associate( request, - new IOnAssociateCallback.Stub() { - + new IFindDeviceCallback.Stub() { @Override - public void onSuccess(PendingIntent launcher) throws RemoteException { + public void onSuccess(PendingIntent launcher) { finalHandler.post(() -> { callback.onDeviceFound(launcher.getIntentSender()); }); } @Override - public void onFailure(CharSequence reason) throws RemoteException { + public void onFailure(CharSequence reason) { finalHandler.post(() -> callback.onFailure(reason)); } }, diff --git a/core/java/android/companion/ICompanionDeviceManagerService.aidl b/core/java/android/companion/ICompanionDeviceDiscoveryService.aidl index ff2a7eb957f0..4d779639888e 100644 --- a/core/java/android/companion/ICompanionDeviceManagerService.aidl +++ b/core/java/android/companion/ICompanionDeviceDiscoveryService.aidl @@ -17,13 +17,14 @@ package android.companion; import android.companion.AssociationRequest; -import android.companion.IOnAssociateCallback; - +import android.companion.ICompanionDeviceDiscoveryServiceCallback; +import android.companion.IFindDeviceCallback; /** @hide */ -interface ICompanionDeviceManagerService { +interface ICompanionDeviceDiscoveryService { void startDiscovery( in AssociationRequest request, - in IOnAssociateCallback callback, - in String callingPackage); + in String callingPackage, + in IFindDeviceCallback findCallback, + in ICompanionDeviceDiscoveryServiceCallback serviceCallback); } diff --git a/core/java/android/companion/ICompanionDeviceManagerServiceCallback.aidl b/core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl index c9dd345341b2..7af708e94d97 100644 --- a/core/java/android/companion/ICompanionDeviceManagerServiceCallback.aidl +++ b/core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl @@ -16,9 +16,7 @@ package android.companion; -import android.bluetooth.BluetoothDevice; - /** @hide */ -interface ICompanionDeviceManagerServiceCallback { - void onDeviceSelected(in BluetoothDevice device); +interface ICompanionDeviceDiscoveryServiceCallback { + void onDeviceSelected(String packageName, int userId); } diff --git a/core/java/android/companion/ICompanionDeviceManager.aidl b/core/java/android/companion/ICompanionDeviceManager.aidl index 065e31be9adf..1d30ada25c62 100644 --- a/core/java/android/companion/ICompanionDeviceManager.aidl +++ b/core/java/android/companion/ICompanionDeviceManager.aidl @@ -16,7 +16,7 @@ package android.companion; -import android.companion.IOnAssociateCallback; +import android.companion.IFindDeviceCallback; import android.companion.AssociationRequest; /** @@ -26,8 +26,8 @@ import android.companion.AssociationRequest; */ interface ICompanionDeviceManager { void associate(in AssociationRequest request, - in IOnAssociateCallback callback, - in String callingPackage); //TODO int userId? + in IFindDeviceCallback callback, + in String callingPackage); //TODO add these // boolean haveNotificationAccess(String packageName); diff --git a/core/java/android/companion/IOnAssociateCallback.aidl b/core/java/android/companion/IFindDeviceCallback.aidl index 4867eadd2577..919e15198efa 100644 --- a/core/java/android/companion/IOnAssociateCallback.aidl +++ b/core/java/android/companion/IFindDeviceCallback.aidl @@ -19,7 +19,7 @@ package android.companion; import android.app.PendingIntent; /** @hide */ -interface IOnAssociateCallback { +interface IFindDeviceCallback { void onSuccess(in PendingIntent launcher); void onFailure(in CharSequence reason); } diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 028a7bcf9539..b0505ac4a3a2 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -669,13 +669,14 @@ public class Intent implements Parcelable, Cloneable { * preview. {@link #getClipData} contains an optional list of content URIs * if there is more than one item to preview. {@link #EXTRA_INDEX} is an * optional index of the URI in the clip data to show first. - * If {@link #EXTRA_QUICK_VIEW_PLAIN} is true, then the quick viewer should show - * basic UI without any extra features other than quick viewing the passed items. - * Especially, the quick viewer should not let users open the passed files - * in other apps, which includes sharing, opening, editing, printing, etc in the - * plain mode. + * <p>By default quick viewers are supposed to be lightweight and focus on + * previewing the content only. They should not expose features such as printing, + * opening in an external app, deleting, rotating, casting, etc. + * However, if {@link #EXTRA_QUICK_VIEW_ADVANCED} is true, then the quick viewer + * may show advanced UI which includes convenience actions suitable for the passed + * Uris. * <p>Output: nothing. - * @see #EXTRA_QUICK_VIEW_HIDE_DEFAULT_ACTIONS + * @see #EXTRA_QUICK_VIEW_ADVANCED * @see #EXTRA_INDEX */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) @@ -4413,19 +4414,15 @@ public class Intent implements Parcelable, Cloneable { public static final String EXTRA_INDEX = "android.intent.extra.INDEX"; /** - * Shows a plain quick viewer UI which doesn't provide any extra features other than - * quick viewing the items. - * - * <p>Especially, the quick viewer should not let users open the quick viewed files - * in other apps, which includes sharing, opening, editing, printing, etc. - * - * <p>This feature is optional, and may not be handled by all quick viewers. + * Tells the quick viewer to show additional UI actions suitable for the passed Uris, + * such as opening in other apps, sharing, opening, editing, printing, deleting, + * casting, etc. * * <p>The value is boolean. By default false. * @see ACTION_QUICK_VIEW */ - public static final String EXTRA_QUICK_VIEW_PLAIN = - "android.intent.extra.QUICK_VIEW_PLAIN"; + public static final String EXTRA_QUICK_VIEW_ADVANCED = + "android.intent.extra.QUICK_VIEW_ADVANCED"; /** * Optional boolean extra indicating whether quiet mode has been switched on or off. diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java index c8f64061e6fc..40deeae28335 100644 --- a/core/java/android/content/pm/LauncherApps.java +++ b/core/java/android/content/pm/LauncherApps.java @@ -37,6 +37,7 @@ import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; +import android.graphics.drawable.MaskableIconDrawable; import android.os.Bundle; import android.os.Handler; import android.os.Looper; @@ -803,7 +804,15 @@ public class LauncherApps { } try { final Bitmap bmp = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor()); - return (bmp == null) ? null : new BitmapDrawable(mContext.getResources(), bmp); + if (bmp != null) { + BitmapDrawable dr = new BitmapDrawable(mContext.getResources(), bmp); + if (shortcut.hasMaskableBitmap()) { + return new MaskableIconDrawable(null, dr); + } else { + return dr; + } + } + return null; } finally { try { pfd.close(); @@ -821,7 +830,8 @@ public class LauncherApps { return loadDrawableResourceFromPackage(shortcut.getPackage(), icon.getResId(), shortcut.getUserHandle(), density); } - case Icon.TYPE_BITMAP: { + case Icon.TYPE_BITMAP: + case Icon.TYPE_BITMAP_MASKABLE: { return icon.loadDrawable(mContext); } default: diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java index b4dcdf7e4e51..f1f268306bb2 100644 --- a/core/java/android/content/pm/ShortcutInfo.java +++ b/core/java/android/content/pm/ShortcutInfo.java @@ -92,6 +92,9 @@ public final class ShortcutInfo implements Parcelable { public static final int FLAG_IMMUTABLE = 1 << 8; /** @hide */ + public static final int FLAG_MASKABLE_BITMAP = 1 << 9; + + /** @hide */ @IntDef(flag = true, value = { FLAG_DYNAMIC, @@ -103,6 +106,7 @@ public final class ShortcutInfo implements Parcelable { FLAG_DISABLED, FLAG_STRINGS_RESOLVED, FLAG_IMMUTABLE, + FLAG_MASKABLE_BITMAP, }) @Retention(RetentionPolicy.SOURCE) public @interface ShortcutFlags {} @@ -690,6 +694,7 @@ public final class ShortcutInfo implements Parcelable { switch (icon.getType()) { case Icon.TYPE_RESOURCE: case Icon.TYPE_BITMAP: + case Icon.TYPE_BITMAP_MASKABLE: break; // OK default: throw getInvalidIconException(); @@ -815,8 +820,9 @@ public final class ShortcutInfo implements Parcelable { * <p>Tints set with {@link Icon#setTint} or {@link Icon#setTintList} are not supported * and will be ignored. * - * <p>Only icons created with {@link Icon#createWithBitmap(Bitmap)} and - * {@link Icon#createWithResource} are supported. + * <p>Only icons created with {@link Icon#createWithBitmap(Bitmap)}, + * {@link Icon#createWithMaskableBitmap(Bitmap)} + * and {@link Icon#createWithResource} are supported. * Other types, such as URI-based icons, are not supported. * * @see LauncherApps#getShortcutIconDrawable(ShortcutInfo, int) @@ -1442,6 +1448,15 @@ public final class ShortcutInfo implements Parcelable { } /** + * Return whether a shortcut's icon is maskable. + * + * @hide internal/unit tests only + */ + public boolean hasMaskableBitmap() { + return hasFlags(FLAG_MASKABLE_BITMAP); + } + + /** * Return whether a shortcut only contains "key" information only or not. If true, only the * following fields are available. * <ul> diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index acb1d07c36a4..719a9577f80e 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -2998,8 +2998,8 @@ 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(NetworkCallback)}. + * {@link NetworkCallback#onUnavailable()} callback is called. The request must + * 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 @@ -3011,10 +3011,7 @@ public class ConnectivityManager { * the callbacks must not be shared - they uniquely specify * this request. * @param timeoutMs The time in milliseconds to attempt looking for a suitable network - * before {@link NetworkCallback#unavailable} is called. - * - * TODO: Make timeouts work and then unhide this method. - * + * before {@link NetworkCallback#onUnavailable()} is called. * @hide */ public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback, @@ -3024,13 +3021,6 @@ public class ConnectivityManager { } /** - * The maximum number of milliseconds the framework will look for a suitable network - * during a timeout-equiped call to {@link requestNetwork}. - * {@hide} - */ - public final static int MAX_NETWORK_REQUEST_TIMEOUT_MS = 100 * 60 * 1000; - - /** * The lookup key for a {@link Network} object included with the intent after * successfully finding a network for the applications request. Retrieve it with * {@link android.content.Intent#getParcelableExtra(String)}. diff --git a/core/java/android/net/NetworkKey.java b/core/java/android/net/NetworkKey.java index e5f0bf000f64..31a74dc77250 100644 --- a/core/java/android/net/NetworkKey.java +++ b/core/java/android/net/NetworkKey.java @@ -24,6 +24,7 @@ import android.net.wifi.WifiSsid; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; +import android.util.Log; import java.util.Objects; @@ -41,6 +42,8 @@ import java.util.Objects; // etc.) so that clients can pull out these details depending on the type of network. public class NetworkKey implements Parcelable { + private static final String TAG = "NetworkKey"; + /** A wifi network, for which {@link #wifiKey} will be populated. */ public static final int TYPE_WIFI = 1; @@ -59,13 +62,28 @@ public class NetworkKey implements Parcelable { /** * Constructs a new NetworkKey for the given wifi {@link ScanResult}. * - * @throws IllegalArgumentException if the given ScanResult is malformed + * @return A new {@link NetworkKey} instance or <code>null</code> if the given + * {@link ScanResult} instance is malformed. * @hide */ - public static NetworkKey createFromScanResult(ScanResult result) { - return new NetworkKey( - new WifiKey( - '"' + result.wifiSsid.toString() + '"', result.BSSID)); + @Nullable + public static NetworkKey createFromScanResult(@Nullable ScanResult result) { + if (result != null && result.wifiSsid != null) { + final String ssid = result.wifiSsid.toString(); + final String bssid = result.BSSID; + if (!TextUtils.isEmpty(ssid) && !ssid.equals(WifiSsid.NONE) + && !TextUtils.isEmpty(bssid)) { + WifiKey wifiKey; + try { + wifiKey = new WifiKey(String.format("\"%s\"", ssid), bssid); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Unable to create WifiKey.", e); + return null; + } + return new NetworkKey(wifiKey); + } + } + return null; } /** @@ -83,7 +101,14 @@ public class NetworkKey implements Parcelable { final String bssid = wifiInfo.getBSSID(); if (!TextUtils.isEmpty(ssid) && !ssid.equals(WifiSsid.NONE) && !TextUtils.isEmpty(bssid)) { - return new NetworkKey(new WifiKey(ssid, bssid)); + WifiKey wifiKey; + try { + wifiKey = new WifiKey(ssid, bssid); + } catch (IllegalArgumentException e) { + Log.e(TAG, "Unable to create WifiKey.", e); + return null; + } + return new NetworkKey(wifiKey); } } return null; diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java index 11b960643e5a..ee8eed1906f4 100644 --- a/core/java/android/preference/SeekBarVolumizer.java +++ b/core/java/android/preference/SeekBarVolumizer.java @@ -348,8 +348,8 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba if (msg.what == UPDATE_SLIDER) { if (mSeekBar != null) { mLastProgress = msg.arg1; - mLastAudibleStreamVolume = Math.abs(msg.arg2); - final boolean muted = msg.arg2 < 0; + mLastAudibleStreamVolume = msg.arg2; + final boolean muted = ((Boolean)msg.obj).booleanValue(); if (muted != mMuted) { mMuted = muted; if (mCallback != null) { @@ -362,8 +362,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba } public void postUpdateSlider(int volume, int lastAudibleVolume, boolean mute) { - final int arg2 = lastAudibleVolume * (mute ? -1 : 1); - obtainMessage(UPDATE_SLIDER, volume, arg2).sendToTarget(); + obtainMessage(UPDATE_SLIDER, volume, lastAudibleVolume, new Boolean(mute)).sendToTarget(); } } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 2dfba28ad6e3..9ecc63896e2f 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -6628,6 +6628,14 @@ public final class Settings { "lock_screen_show_notifications"; /** + * This preference stores the last stack active task time for each user, which affects what + * tasks will be visible in Overview. + * @hide + */ + public static final String OVERVIEW_LAST_STACK_ACTIVE_TIME = + "overview_last_stack_active_time"; + + /** * List of TV inputs that are currently hidden. This is a string * containing the IDs of all hidden TV inputs. Each ID is encoded by * {@link android.net.Uri#encode(String)} and separated by ':'. diff --git a/core/java/android/text/Emoji.java b/core/java/android/text/Emoji.java index b6d720d453e9..83810b03b463 100644 --- a/core/java/android/text/Emoji.java +++ b/core/java/android/text/Emoji.java @@ -164,6 +164,8 @@ public class Emoji { public static int VARIATION_SELECTOR_16 = 0xFE0F; + public static int CANCEL_TAG = 0xE007F; + // Returns true if the given code point is regional indicator symbol. public static boolean isRegionalIndicatorSymbol(int codepoint) { return 0x1F1E6 <= codepoint && codepoint <= 0x1F1FF; @@ -188,4 +190,13 @@ public class Emoji { public static boolean isKeycapBase(int codePoint) { return ('0' <= codePoint && codePoint <= '9') || codePoint == '#' || codePoint == '*'; } + + /** + * Returns true if the character can be a part of tag_spec in emoji tag sequence. + * + * Note that 0xE007F (CANCEL TAG) is not included. + */ + public static boolean isTagSpecChar(int codePoint) { + return 0xE0020 <= codePoint && codePoint <= 0xE007E; + } } diff --git a/core/java/android/text/method/BaseKeyListener.java b/core/java/android/text/method/BaseKeyListener.java index 90559dcdbcf4..5f0a46d815ea 100644 --- a/core/java/android/text/method/BaseKeyListener.java +++ b/core/java/android/text/method/BaseKeyListener.java @@ -145,8 +145,11 @@ public abstract class BaseKeyListener extends MetaKeyKeyListener // The number of following RIS code points is even. final int STATE_EVEN_NUMBERED_RIS = 11; + // The offset is in emoji tag sequence. + final int STATE_IN_TAG_SEQUENCE = 12; + // The state machine has been stopped. - final int STATE_FINISHED = 12; + final int STATE_FINISHED = 13; int deleteCharCount = 0; // Char count to be deleted by backspace. int lastSeenVSCharCount = 0; // Char count of previous variation selector. @@ -173,6 +176,8 @@ public abstract class BaseKeyListener extends MetaKeyKeyListener state = STATE_BEFORE_KEYCAP; } else if (Emoji.isEmoji(codePoint)) { state = STATE_BEFORE_EMOJI; + } else if (codePoint == Emoji.CANCEL_TAG) { + state = STATE_IN_TAG_SEQUENCE; } else { state = STATE_FINISHED; } @@ -275,6 +280,20 @@ public abstract class BaseKeyListener extends MetaKeyKeyListener state = STATE_FINISHED; } break; + case STATE_IN_TAG_SEQUENCE: + if (Emoji.isTagSpecChar(codePoint)) { + deleteCharCount += 2; /* Char count of emoji tag spec character. */ + // Keep the same state. + } else if (Emoji.isEmoji(codePoint)) { + deleteCharCount += Character.charCount(codePoint); + state = STATE_FINISHED; + } else { + // Couldn't find tag_base character. Delete the last tag_term character. + deleteCharCount = 2; // for U+E007F + state = STATE_FINISHED; + } + // TODO: Need handle emoji variation selectors. Issue 35224297 + break; default: throw new IllegalArgumentException("state " + state + " is unknown"); } diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index 2129039b1b8c..5f55bdc0e0d3 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -1008,7 +1008,6 @@ public final class MotionEvent extends InputEvent implements Parcelable { * </p> * * @see #getAxisValue(int, int) - * {@hide} */ public static final int AXIS_SCROLL = 26; diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java index d195c885dc6f..9ce23e631451 100644 --- a/core/java/android/view/ViewStructure.java +++ b/core/java/android/view/ViewStructure.java @@ -25,7 +25,8 @@ import android.view.autofill.AutoFillValue; /** * Container for storing additional per-view data generated by {@link View#onProvideStructure - * View.onProvideStructure}. + * View.onProvideStructure} and {@link View#onProvideAutoFillStructure + * View.onProvideAutoFillStructure}. */ public abstract class ViewStructure { @@ -33,7 +34,9 @@ public abstract class ViewStructure { * Flag used when adding virtual views for auto-fill, it indicates the contents of the view * (such as * {@link android.app.assist.AssistStructure.ViewNode#getText()} and * {@link android.app.assist.AssistStructure.ViewNode#getAutoFillValue()}) - * can be passed to the {@link android.service.autofill.AutoFillService}. + * can be passed to the {@link + * android.service.autofill.AutoFillService#onFillRequest(android.app.assist.AssistStructure, + * Bundle, android.os.CancellationSignal, android.service.autofill.FillCallback)} call. */ public static final int AUTO_FILL_FLAG_SANITIZED = 0x1; @@ -275,7 +278,7 @@ public abstract class ViewStructure { * * @param index child index * @param virtualId id identifying the virtual child inside the custom view. - * @param flags currently {@code 0}. + * @param flags currently {@code 0} or {@link #AUTO_FILL_FLAG_SANITIZED}. */ // TODO(b/33197203, b/33802548): add CTS/unit test public abstract ViewStructure newChild(int index, int virtualId, int flags); @@ -296,7 +299,7 @@ public abstract class ViewStructure { * * @param index child index * @param virtualId id identifying the virtual child inside the custom view. - * @param flags currently {@code 0}. + * @param flags currently {@code 0} or {@link #AUTO_FILL_FLAG_SANITIZED}. */ // TODO(b/33197203, b/33802548): add CTS/unit test public abstract ViewStructure asyncNewChild(int index, int virtualId, int flags); diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java index fcb4c7b48125..3d012bf24f7a 100644 --- a/core/java/com/android/server/SystemConfig.java +++ b/core/java/com/android/server/SystemConfig.java @@ -109,6 +109,10 @@ public class SystemConfig { // background while in data-usage save mode, as read from the configuration files. final ArraySet<String> mAllowInDataUsageSave = new ArraySet<>(); + // These are the packages that are white-listed to be able to run background location + // without throttling, as read from the configuration files. + final ArraySet<String> mAllowUnthrottledLocation = new ArraySet<>(); + // These are the action strings of broadcasts which are whitelisted to // be delivered anonymously even to apps which target O+. final ArraySet<String> mAllowImplicitBroadcasts = new ArraySet<>(); @@ -182,6 +186,10 @@ public class SystemConfig { return mAllowInDataUsageSave; } + public ArraySet<String> getAllowUnthrottledLocation() { + return mAllowUnthrottledLocation; + } + public ArraySet<String> getLinkedApps() { return mLinkedApps; } @@ -446,6 +454,17 @@ public class SystemConfig { XmlUtils.skipCurrentTag(parser); continue; + } else if ("allow-unthrottled-location".equals(name) && allowAll) { + String pkgname = parser.getAttributeValue(null, "package"); + if (pkgname == null) { + Slog.w(TAG, "<allow-unthrottled-location> without package in " + + permFile + " at " + parser.getPositionDescription()); + } else { + mAllowUnthrottledLocation.add(pkgname); + } + XmlUtils.skipCurrentTag(parser); + continue; + } else if ("allow-implicit-broadcast".equals(name) && allowAll) { String action = parser.getAttributeValue(null, "action"); if (action == null) { diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index cd02fbbedb7e..97fbfa5a55b6 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1813,6 +1813,22 @@ android:description="@string/permdesc_systemAlertWindow" android:protectionLevel="signature|preinstalled|appop|pre23|development" /> + <!-- Allows an app to run in the background. + <p>Protection level: signature + --> + <permission android:name="android.permission.RUN_IN_BACKGROUND" + android:label="@string/permlab_runInBackground" + android:description="@string/permdesc_runInBackground" + android:protectionLevel="signature" /> + + <!-- Allows an app to use data in the background. + <p>Protection level: signature + --> + <permission android:name="android.permission.USE_DATA_IN_BACKGROUND" + android:label="@string/permlab_useDataInBackground" + android:description="@string/permdesc_useDataInBackground" + android:protectionLevel="signature" /> + <!-- ================================== --> <!-- Permissions affecting the system wallpaper --> <!-- ================================== --> @@ -2996,7 +3012,7 @@ any metadata and intents attached. @hide --> <permission android:name="android.permission.ACCESS_NOTIFICATIONS" - android:protectionLevel="signature|privileged" /> + android:protectionLevel="signature|privileged|appop" /> <!-- Marker permission for applications that wish to access notification policy. <p>Protection level: normal diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 72a2e43bc8c8..fcb0e08141e4 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1286,6 +1286,16 @@ <item>com.android.networkrecommendation</item> </string-array> + <!-- The package name of the default network recommendation app. + A network recommendation provider must: + * Be granted the SCORE_NETWORKS permission. + * Include a Service for the android.net.scoring.RECOMMEND_NETWORKS action + protected by the BIND_NETWORK_RECOMMENDATION_SERVICE permission. + + This must be set to a valid network recommendation app. + --> + <string name="config_defaultNetworkRecommendationProviderPackage" translatable="false">com.android.networkrecommendation</string> + <!-- Whether to enable Hardware FLP overlay which allows Hardware FLP to be replaced by an app at run-time. When disabled, only the config_hardwareFlpPackageName package will be searched for Hardware Flp, diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 23098668c082..8faa76cda808 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -816,6 +816,16 @@ <string name="permdesc_systemAlertWindow">This app can appear on top of other apps or other parts of the screen. This may interfere with normal app usage and change the way that other apps appear.</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_runInBackground">run in the background</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_runInBackground">This app can run in the background. This may drain battery faster.</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_useDataInBackground">use data in the background</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_useDataInBackground">This app can use data in the background. This may increase data usage.</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_persistentActivity">make app always run</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permdesc_persistentActivity" product="tablet">Allows the app to make parts of itself persistent in memory. This can limit memory available to other apps slowing down the tablet.</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 1324e383618d..0d63a1e48420 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2790,6 +2790,7 @@ <!-- Network Recommendation --> <java-symbol type="array" name="config_networkRecommendationPackageNames" /> + <java-symbol type="string" name="config_defaultNetworkRecommendationProviderPackage" /> <!-- Whether allow 3rd party apps on internal storage. --> <java-symbol type="bool" name="config_allow3rdPartyAppOnInternal" /> diff --git a/core/tests/coretests/src/android/net/NetworkKeyTest.java b/core/tests/coretests/src/android/net/NetworkKeyTest.java index 1afe9da2bfe6..fff23a04db9f 100644 --- a/core/tests/coretests/src/android/net/NetworkKeyTest.java +++ b/core/tests/coretests/src/android/net/NetworkKeyTest.java @@ -4,6 +4,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.mockito.Mockito.when; +import android.net.wifi.ScanResult; import android.net.wifi.WifiInfo; import android.net.wifi.WifiSsid; import android.support.test.runner.AndroidJUnit4; @@ -17,7 +18,9 @@ import org.mockito.MockitoAnnotations; @RunWith(AndroidJUnit4.class) public class NetworkKeyTest { private static final String VALID_SSID = "\"ssid1\""; + private static final String VALID_UNQUOTED_SSID = "ssid1"; private static final String VALID_BSSID = "00:00:00:00:00:00"; + private static final String INVALID_BSSID = "invalid_bssid"; @Mock private WifiInfo mWifiInfo; @Before @@ -64,6 +67,13 @@ public class NetworkKeyTest { } @Test + public void createFromWifi_invalidBssid() throws Exception { + when(mWifiInfo.getSSID()).thenReturn(VALID_SSID); + when(mWifiInfo.getBSSID()).thenReturn(INVALID_BSSID); + assertNull(NetworkKey.createFromWifiInfo(mWifiInfo)); + } + + @Test public void createFromWifi_validWifiInfo() throws Exception { when(mWifiInfo.getSSID()).thenReturn(VALID_SSID); when(mWifiInfo.getBSSID()).thenReturn(VALID_BSSID); @@ -72,4 +82,72 @@ public class NetworkKeyTest { final NetworkKey actual = NetworkKey.createFromWifiInfo(mWifiInfo); assertEquals(expected, actual); } + + @Test + public void createFromScanResult_nullInput() { + assertNull(NetworkKey.createFromScanResult(null)); + } + + @Test + public void createFromScanResult_nullWifiSsid() { + ScanResult scanResult = new ScanResult(); + scanResult.BSSID = VALID_BSSID; + + assertNull(NetworkKey.createFromScanResult(scanResult)); + } + + @Test + public void createFromScanResult_emptyWifiSsid() { + ScanResult scanResult = new ScanResult(); + scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded(""); + scanResult.BSSID = VALID_BSSID; + + assertNull(NetworkKey.createFromScanResult(scanResult)); + } + + @Test + public void createFromScanResult_noneWifiSsid() { + ScanResult scanResult = new ScanResult(); + scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded(WifiSsid.NONE); + scanResult.BSSID = VALID_BSSID; + + assertNull(NetworkKey.createFromScanResult(scanResult)); + } + + @Test + public void createFromScanResult_nullBssid() { + ScanResult scanResult = new ScanResult(); + scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded(VALID_UNQUOTED_SSID); + + assertNull(NetworkKey.createFromScanResult(scanResult)); + } + + @Test + public void createFromScanResult_emptyBssid() { + ScanResult scanResult = new ScanResult(); + scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded(VALID_UNQUOTED_SSID); + scanResult.BSSID = ""; + + assertNull(NetworkKey.createFromScanResult(scanResult)); + } + + @Test + public void createFromScanResult_invalidBssid() { + ScanResult scanResult = new ScanResult(); + scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded(VALID_UNQUOTED_SSID); + scanResult.BSSID = INVALID_BSSID; + + assertNull(NetworkKey.createFromScanResult(scanResult)); + } + + @Test + public void createFromScanResult_validWifiSsid() { + ScanResult scanResult = new ScanResult(); + scanResult.wifiSsid = WifiSsid.createFromAsciiEncoded(VALID_UNQUOTED_SSID); + scanResult.BSSID = VALID_BSSID; + + NetworkKey expected = new NetworkKey(new WifiKey(VALID_SSID, VALID_BSSID)); + NetworkKey actual = NetworkKey.createFromScanResult(scanResult); + assertEquals(expected, actual); + } } diff --git a/core/tests/coretests/src/android/text/method/BackspaceTest.java b/core/tests/coretests/src/android/text/method/BackspaceTest.java index a260e947958e..864b48a79bb0 100644 --- a/core/tests/coretests/src/android/text/method/BackspaceTest.java +++ b/core/tests/coretests/src/android/text/method/BackspaceTest.java @@ -37,23 +37,12 @@ public class BackspaceTest extends KeyListenerTestCase { // Sync the state to the TextView and call onKeyDown with KEYCODE_DEL key event. // Then update the state to the result of TextView. private void backspace(final EditorState state, int modifiers) { - mActivity.runOnUiThread(new Runnable() { - public void run() { - mTextView.setText(state.mText, BufferType.EDITABLE); - mTextView.setKeyListener(mKeyListener); - mTextView.setSelection(state.mSelectionStart, state.mSelectionEnd); - } - }); - mInstrumentation.waitForIdleSync(); - assertTrue(mTextView.hasWindowFocus()); + mTextView.setText(state.mText, BufferType.EDITABLE); + mTextView.setKeyListener(mKeyListener); + mTextView.setSelection(state.mSelectionStart, state.mSelectionEnd); final KeyEvent keyEvent = getKey(KeyEvent.KEYCODE_DEL, modifiers); - mActivity.runOnUiThread(new Runnable() { - public void run() { - mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent); - } - }); - mInstrumentation.waitForIdleSync(); + mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent); state.mText = mTextView.getText(); state.mSelectionStart = mTextView.getSelectionStart(); @@ -247,6 +236,51 @@ public class BackspaceTest extends KeyListenerTestCase { state.assertEquals("U+1F1FA U+1F1F8 |"); backspace(state, 0); state.assertEquals("|"); + + // Incomplete sequence. (no tag_term: U+E007E) + state.setByString("'a' U+1F3F4 U+E0067 'b' |"); + backspace(state, 0); + state.assertEquals("'a' U+1F3F4 U+E0067 |"); + backspace(state, 0); + state.assertEquals("'a' U+1F3F4 |"); + backspace(state, 0); + state.assertEquals("'a' |"); + + // No tag_base + state.setByString("'a' U+E0067 U+E007F 'b' |"); + backspace(state, 0); + state.assertEquals("'a' U+E0067 U+E007F |"); + backspace(state, 0); + state.assertEquals("'a' U+E0067 |"); + backspace(state, 0); + state.assertEquals("'a' |"); + + // Isolated tag chars + state.setByString("'a' U+E0067 U+E0067 'b' |"); + backspace(state, 0); + state.assertEquals("'a' U+E0067 U+E0067 |"); + backspace(state, 0); + state.assertEquals("'a' U+E0067 |"); + backspace(state, 0); + state.assertEquals("'a' |"); + + // Isolated tab term. + state.setByString("'a' U+E007F U+E007F 'b' |"); + backspace(state, 0); + state.assertEquals("'a' U+E007F U+E007F |"); + backspace(state, 0); + state.assertEquals("'a' U+E007F |"); + backspace(state, 0); + state.assertEquals("'a' |"); + + // Immediate tag_term after tag_base + state.setByString("'a' U+1F3F4 U+E007F U+1F3F4 U+E007F 'b' |"); + backspace(state, 0); + state.assertEquals("'a' U+1F3F4 U+E007F U+1F3F4 U+E007F |"); + backspace(state, 0); + state.assertEquals("'a' U+1F3F4 U+E007F |"); + backspace(state, 0); + state.assertEquals("'a' |"); } @SmallTest diff --git a/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java index 1990fd021203..839d380f79b9 100644 --- a/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java +++ b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java @@ -37,23 +37,12 @@ public class ForwardDeleteTest extends KeyListenerTestCase { // Sync the state to the TextView and call onKeyDown with KEYCODE_FORWARD_DEL key event. // Then update the state to the result of TextView. private void forwardDelete(final EditorState state, int modifiers) { - mActivity.runOnUiThread(new Runnable() { - public void run() { - mTextView.setText(state.mText, BufferType.EDITABLE); - mTextView.setKeyListener(mKeyListener); - mTextView.setSelection(state.mSelectionStart, state.mSelectionEnd); - } - }); - mInstrumentation.waitForIdleSync(); - assertTrue(mTextView.hasWindowFocus()); + mTextView.setText(state.mText, BufferType.EDITABLE); + mTextView.setKeyListener(mKeyListener); + mTextView.setSelection(state.mSelectionStart, state.mSelectionEnd); final KeyEvent keyEvent = getKey(KeyEvent.KEYCODE_FORWARD_DEL, modifiers); - mActivity.runOnUiThread(new Runnable() { - public void run() { - mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent); - } - }); - mInstrumentation.waitForIdleSync(); + mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent); state.mText = mTextView.getText(); state.mSelectionStart = mTextView.getSelectionStart(); @@ -186,6 +175,46 @@ public class ForwardDeleteTest extends KeyListenerTestCase { state.assertEquals("| U+1F1FA"); forwardDelete(state, 0); state.assertEquals("|"); + + // Incomplete sequence. (no tag_term:U+E007E) + state.setByString("| 'a' U+1F3F4 U+E0067 'b'"); + forwardDelete(state, 0); + state.assertEquals("| U+1F3F4 U+E0067 'b'"); + forwardDelete(state, 0); + state.assertEquals("| 'b'"); + + // No tag_base + state.setByString("| 'a' U+E0067 U+E007F 'b'"); + forwardDelete(state, 0); + state.assertEquals("| 'b'"); + + // Isolated tag chars + state.setByString("| 'a' U+E0067 U+E0067 'b'"); + forwardDelete(state, 0); + state.assertEquals("| 'b'"); + + // Isolated tag base. + state.setByString("| 'a' U+1F3F4 U+1F3F4 'b'"); + forwardDelete(state, 0); + state.assertEquals("| U+1F3F4 U+1F3F4 'b'"); + forwardDelete(state, 0); + state.assertEquals("| U+1F3F4 'b'"); + forwardDelete(state, 0); + state.assertEquals("| 'b'"); + + // Isolated tab term. + state.setByString("| 'a' U+E007F U+E007F 'b'"); + forwardDelete(state, 0); + state.assertEquals("| 'b'"); + + // Immediate tag_term after tag_base + state.setByString("| 'a' U+1F3F4 U+E007F U+1F3F4 U+E007F 'b'"); + forwardDelete(state, 0); + state.assertEquals("| U+1F3F4 U+E007F U+1F3F4 U+E007F 'b'"); + forwardDelete(state, 0); + state.assertEquals("| U+1F3F4 U+E007F 'b'"); + forwardDelete(state, 0); + state.assertEquals("| 'b'"); } @SmallTest diff --git a/core/tests/coretests/src/android/text/method/KeyListenerTestCase.java b/core/tests/coretests/src/android/text/method/KeyListenerTestCase.java index 4b4e7afdb636..f005d7b02a62 100644 --- a/core/tests/coretests/src/android/text/method/KeyListenerTestCase.java +++ b/core/tests/coretests/src/android/text/method/KeyListenerTestCase.java @@ -17,41 +17,26 @@ package android.text.method; import android.app.Instrumentation; -import android.test.ActivityInstrumentationTestCase2; -import android.text.format.DateUtils; +import android.test.InstrumentationTestCase; import android.view.KeyEvent; import android.widget.EditText; -import android.widget.TextViewActivity; import com.android.frameworks.coretests.R; -public abstract class KeyListenerTestCase extends - ActivityInstrumentationTestCase2<TextViewActivity> { +public abstract class KeyListenerTestCase extends InstrumentationTestCase { - protected TextViewActivity mActivity; protected Instrumentation mInstrumentation; protected EditText mTextView; public KeyListenerTestCase() { - super(TextViewActivity.class); } @Override protected void setUp() throws Exception { super.setUp(); - mActivity = getActivity(); mInstrumentation = getInstrumentation(); - mTextView = (EditText) mActivity.findViewById(R.id.textview); - - mActivity.runOnUiThread(new Runnable() { - public void run() { - // Ensure that the screen is on for this test. - mTextView.setKeepScreenOn(true); - } - }); - - assertTrue(mActivity.waitForWindowFocus(5 * DateUtils.SECOND_IN_MILLIS)); + mTextView = new EditText(mInstrumentation.getContext()); } protected static KeyEvent getKey(int keycode, int metaState) { diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 85c3c1c7068d..5008a5f8c5c2 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -640,6 +640,8 @@ public class MediaPlayer extends PlayerBase private UUID mDrmUUID; private final Object mDrmLock = new Object(); private DrmInfo mDrmInfo; + private MediaDrm mDrmObj; + private byte[] mDrmSessionId; private boolean mDrmInfoResolved; private boolean mActiveDrmScheme; private boolean mDrmConfigAllowed; @@ -1960,6 +1962,7 @@ public class MediaPlayer extends PlayerBase mOnSubtitleDataListener = null; // Modular DRM clean up + mOnDrmConfigListener = null; mOnDrmInfoHandlerDelegate = null; mOnDrmPreparedHandlerDelegate = null; resetDrmState(); @@ -3171,7 +3174,7 @@ public class MediaPlayer extends PlayerBase onDrmInfoHandlerDelegate.notifyClient(drmInfo); } } else { - Log.w(TAG, "MEDIA_DRM_INFO msg.obj NONE; UNEXPECTED" + msg.obj); + Log.w(TAG, "MEDIA_DRM_INFO msg.obj of unexpected type " + msg.obj); } return; @@ -3846,17 +3849,34 @@ public class MediaPlayer extends PlayerBase * and setDrmPropertyString. * */ - public static abstract class OnDrmConfigCallback + public interface OnDrmConfigListener { /** * Called to give the app the opportunity to configure DRM before the session is created * * @param mp the {@code MediaPlayer} associated with this callback */ - public void onDrmConfig(MediaPlayer mp) {} + public void onDrmConfig(MediaPlayer mp); } /** + * Register a callback to be invoked for configuration of the DRM object before + * the session is created. + * The callback will be invoked synchronously half-way into the execution + * of {@link #prepareDrm(UUID uuid)}. + * + * @param listener the callback that will be run + */ + public void setOnDrmConfigListener(OnDrmConfigListener listener) + { + synchronized (mDrmLock) { + mOnDrmConfigListener = listener; + } // synchronized + } + + private OnDrmConfigListener mOnDrmConfigListener; + + /** * Interface definition of a callback to be invoked when the * DRM info becomes available */ @@ -4053,13 +4073,11 @@ public class MediaPlayer extends PlayerBase return drmInfo; } - private native void _prepareDrm(@NonNull byte[] uuid, int mode) - throws UnsupportedSchemeException, ResourceBusyException, NotProvisionedException; /** * Prepares the DRM for the current source * <p> - * If {@code OnDrmConfigCallback} is registered, it will be called half-way into + * If {@code OnDrmConfigListener} is registered, it will be called half-way into * preparation to allow configuration of the DRM properties before opening the * DRM session. Note that the callback is called synchronously in the thread that called * {@code prepareDrm}. It should be used only for a series of {@code getDrmPropertyString} @@ -4087,10 +4105,12 @@ public class MediaPlayer extends PlayerBase * @throws ResourceBusyException if required DRM resources are in use * @throws ProvisioningErrorException if provisioning is required but an attempt failed */ - public void prepareDrm(@NonNull UUID uuid, OnDrmConfigCallback configCallback) + public void prepareDrm(@NonNull UUID uuid) throws UnsupportedSchemeException, ResourceBusyException, ProvisioningErrorException { + Log.v(TAG, "prepareDrm: uuid: " + uuid + " mOnDrmConfigListener: " + mOnDrmConfigListener); + boolean allDoneWithoutProvisioning = false; // get a snapshot as we'll use them outside the lock OnDrmPreparedHandlerDelegate onDrmPreparedHandlerDelegate = null; @@ -4099,58 +4119,46 @@ public class MediaPlayer extends PlayerBase // only allowing if tied to a protected source; might releax for releasing offline keys if (mDrmInfo == null) { - final String msg = String.format("prepareDrm(%s): Wrong usage: " + - "The player must be prepared and DRM " + - "info be retrieved before this call.", uuid); + final String msg = "prepareDrm(): Wrong usage: The player must be prepared and " + + "DRM info be retrieved before this call."; Log.e(TAG, msg); throw new IllegalStateException(msg); } if (mActiveDrmScheme) { - final String msg = String.format("prepareDrm(%s): Wrong usage: There is already " + - "an active DRM scheme with %s.", uuid, mDrmUUID); + final String msg = "prepareDrm(): Wrong usage: There is already " + + "an active DRM scheme with " + mDrmUUID; Log.e(TAG, msg); throw new IllegalStateException(msg); } if (mPrepareDrmInProgress) { - final String msg = String.format("prepareDrm(%s): Wrong usage: There is already " + - "a pending prepareDrm call.", uuid); + final String msg = "prepareDrm(): Wrong usage: There is already " + + "a pending prepareDrm call."; Log.e(TAG, msg); throw new IllegalStateException(msg); } if (mDrmProvisioningInProgress) { - final String msg = String.format("prepareDrm(%s): Unexpectd: Provisioning is " + - "already in progress.", uuid); + final String msg = "prepareDrm(): Unexpectd: Provisioning is already in progress."; Log.e(TAG, msg); throw new IllegalStateException(msg); } + // shouldn't need this; just for safeguard + cleanDrmObj(); + mPrepareDrmInProgress = true; // local copy while the lock is held onDrmPreparedHandlerDelegate = mOnDrmPreparedHandlerDelegate; - if (configCallback != null) { - try { - boolean allowOpenSession = false; // just pre-openSession - _prepareDrm(getByteArrayFromUUID(uuid), allowOpenSession ? 1 : 0); - } catch (IllegalStateException e) { - final String msg = String.format("prepareDrm(): Wrong usage: The player must " + - "be in prepared state to call prepareDrm()."); - Log.e(TAG, msg); - throw new IllegalStateException(msg); - } catch (NotProvisionedException e) { // the pre-config step won't raise this - final String msg = String.format("prepareDrm: Unexpected " + - "NotProvisionedException here."); - Log.e(TAG, msg); - throw new ProvisioningErrorException(msg); - } catch (Exception e) { - Log.w(TAG, String.format("prepareDrm: Exception %s", e)); - throw e; - } finally { - mPrepareDrmInProgress = false; - } + try { + // only creating the DRM object to allow pre-openSession configuration + prepareDrm_createDrmStep(uuid); + } catch (Exception e) { + Log.w(TAG, "prepareDrm(): Exception ", e); + mPrepareDrmInProgress = false; + throw e; } mDrmConfigAllowed = true; @@ -4158,51 +4166,55 @@ public class MediaPlayer extends PlayerBase // call the callback outside the lock - if (configCallback != null) { - configCallback.onDrmConfig(this); + if (mOnDrmConfigListener != null) { + mOnDrmConfigListener.onDrmConfig(this); } synchronized (mDrmLock) { mDrmConfigAllowed = false; + boolean earlyExit = false; try { - boolean allowOpenSession = true; // all in - _prepareDrm(getByteArrayFromUUID(uuid), allowOpenSession ? 1 : 0); + prepareDrm_openSessionStep(uuid); mDrmUUID = uuid; mActiveDrmScheme = true; - mPrepareDrmInProgress = false; - allDoneWithoutProvisioning = true; } catch (IllegalStateException e) { - final String msg = String.format("prepareDrm(%s): Wrong usage: The player must be" + - " in prepared state to call prepareDrm().", uuid); + final String msg = "prepareDrm(): Wrong usage: The player must be " + + "in the prepared state to call prepareDrm()."; Log.e(TAG, msg); + earlyExit = true; throw new IllegalStateException(msg); } catch (NotProvisionedException e) { - Log.w(TAG, String.format("prepareDrm: NotProvisionedException")); + Log.w(TAG, "prepareDrm: NotProvisionedException"); - // handle provisioning internally + // handle provisioning internally; it'll reset mPrepareDrmInProgress boolean result = HandleProvisioninig(uuid); // if blocking mode, we're already done; // if non-blocking mode, we attempted to launch background provisioning if (result == false) { - final String msg = - String.format("prepareDrm: Provisioning was required but failed."); + final String msg = "prepareDrm: Provisioning was required but failed."; Log.e(TAG, msg); + earlyExit = true; throw new ProvisioningErrorException(msg); } - // nothing else to do; // if blocking or non-blocking, HandleProvisioninig does the re-attempt & cleanup } catch (Exception e) { - Log.w(TAG, String.format("prepareDrm: Exception %s", e)); + Log.e(TAG, "prepareDrm: Exception " + e); + earlyExit = true; throw e; } finally { - mPrepareDrmInProgress = false; - } + if (!mDrmProvisioningInProgress) {// if early exit other than provisioning exception + mPrepareDrmInProgress = false; + } + if (earlyExit) { // cleaning up object if didn't succeed + cleanDrmObj(); + } + } // finally } // synchronized @@ -4225,25 +4237,33 @@ public class MediaPlayer extends PlayerBase public void releaseDrm() throws NoDrmSchemeException { + Log.v(TAG, "releaseDrm:"); + synchronized (mDrmLock) { if (!mActiveDrmScheme) { - Log.e(TAG, String.format("releaseDrm(%s): No active DRM scheme to release.")); + Log.e(TAG, "releaseDrm(): No active DRM scheme to release."); throw new NoDrmSchemeException("releaseDrm: No active DRM scheme to release."); - } else { + } + + try { + // we don't have the player's state in this layer. The below call raises + // exception if we're in a non-stopped/idle state. + + // for cleaning native/mediaserver crypto object _releaseDrm(); + // for cleaning client-side MediaDrm object; only called if above has succeeded + cleanDrmObj(); + mActiveDrmScheme = false; + } catch (Exception e) { + Log.w(TAG, "releaseDrm: Exception ", e); + throw e; } } // synchronized } - @NonNull - private native MediaDrm.KeyRequest _getKeyRequest(@NonNull byte[] scope, - @Nullable String mimeType, @MediaDrm.KeyType int keyType, - @Nullable Map<String, String> optionalParameters) - throws NotProvisionedException; - /** * A key request/response exchange occurs between the app and a license server * to obtain or release keys used to decrypt encrypted content. @@ -4284,20 +4304,42 @@ public class MediaPlayer extends PlayerBase @MediaDrm.KeyType int keyType, @Nullable Map<String, String> optionalParameters) throws NoDrmSchemeException { + Log.v(TAG, "getKeyRequest: " + + " scope: " + scope + " mimeType: " + mimeType + + " keyType: " + keyType + " optionalParameters: " + optionalParameters); + synchronized (mDrmLock) { if (!mActiveDrmScheme) { - Log.e(TAG, String.format("getKeyRequest NoDrmSchemeException")); + Log.e(TAG, "getKeyRequest NoDrmSchemeException"); throw new NoDrmSchemeException("getKeyRequest: Has to set a DRM scheme first."); } try { - return _getKeyRequest(scope, mimeType, keyType, optionalParameters); + byte[] scopeOut = (keyType != MediaDrm.KEY_TYPE_RELEASE) ? + mDrmSessionId : // sessionId for KEY_TYPE_STREAMING/OFFLINE + scope; // keySetId for KEY_TYPE_RELEASE + + byte[] initData = (keyType != MediaDrm.KEY_TYPE_RELEASE) ? + scope : // initData for KEY_TYPE_STREAMING/OFFLINE + null; // not used for KEY_TYPE_RELEASE + + HashMap<String, String> hmapOptionalParameters = + (optionalParameters != null) ? + new HashMap<String, String>(optionalParameters) : + null; + + MediaDrm.KeyRequest request = mDrmObj.getKeyRequest(scopeOut, initData, mimeType, + keyType, hmapOptionalParameters); + Log.v(TAG, "getKeyRequest: --> request: " + request); + + return request; + } catch (NotProvisionedException e) { - Log.w(TAG, String.format("getKeyRequest NotProvisionedException: " + - "Unexpected. Shouldn't have reached here.")); + Log.w(TAG, "getKeyRequest NotProvisionedException: " + + "Unexpected. Shouldn't have reached here."); throw new IllegalStateException("getKeyRequest: Unexpected provisioning error."); } catch (Exception e) { - Log.w(TAG, String.format("getKeyRequest Exception %s", e)); + Log.w(TAG, "getKeyRequest Exception " + e); throw e; } @@ -4305,10 +4347,6 @@ public class MediaPlayer extends PlayerBase } - @Nullable - private native byte[] _provideKeyResponse(@Nullable byte[] keySetId, @NonNull byte[] response) - throws DeniedByServerException; - /** * A key response is received from the license server by the app, then it is * provided to the DRM engine plugin using provideKeyResponse. When the @@ -4331,25 +4369,41 @@ public class MediaPlayer extends PlayerBase public byte[] provideKeyResponse(@Nullable byte[] keySetId, @NonNull byte[] response) throws NoDrmSchemeException, DeniedByServerException { + Log.v(TAG, "provideKeyResponse: keySetId: " + keySetId + " response: " + response); + synchronized (mDrmLock) { if (!mActiveDrmScheme) { - Log.e(TAG, String.format("getKeyRequest NoDrmSchemeException")); + Log.e(TAG, "getKeyRequest NoDrmSchemeException"); throw new NoDrmSchemeException("getKeyRequest: Has to set a DRM scheme first."); } try { - return _provideKeyResponse(keySetId, response); + byte[] scope = (keySetId == null) ? + mDrmSessionId : // sessionId for KEY_TYPE_STREAMING/OFFLINE + keySetId; // keySetId for KEY_TYPE_RELEASE + + byte[] keySetResult = mDrmObj.provideKeyResponse(scope, response); + + Log.v(TAG, "provideKeyResponse: keySetId: " + keySetId + " response: " + response + + " --> " + keySetResult); + + + return keySetResult; + + } catch (NotProvisionedException e) { + Log.w(TAG, "provideKeyResponse NotProvisionedException: " + + "Unexpected. Shouldn't have reached here."); + throw new IllegalStateException("provideKeyResponse: " + + "Unexpected provisioning error."); } catch (Exception e) { - Log.w(TAG, String.format("provideKeyResponse Exception %s", e)); + Log.w(TAG, "provideKeyResponse Exception " + e); throw e; } } // synchronized } - private native void _restoreKeys(@NonNull byte[] keySetId); - /** * Restore persisted offline keys into a new session. keySetId identifies the * keys to load, obtained from a prior call to {@link #provideKeyResponse}. @@ -4359,17 +4413,19 @@ public class MediaPlayer extends PlayerBase public void restoreKeys(@NonNull byte[] keySetId) throws NoDrmSchemeException { + Log.v(TAG, "restoreKeys: keySetId: " + keySetId); + synchronized (mDrmLock) { if (!mActiveDrmScheme) { - Log.w(TAG, String.format("restoreKeys NoDrmSchemeException")); + Log.w(TAG, "restoreKeys NoDrmSchemeException"); throw new NoDrmSchemeException("restoreKeys: Has to set a DRM scheme first."); } try { - _restoreKeys(keySetId); + mDrmObj.restoreKeys(mDrmSessionId, keySetId); } catch (Exception e) { - Log.w(TAG, String.format("restoreKeys Exception %s", e)); + Log.w(TAG, "restoreKeys Exception " + e); throw e; } @@ -4377,9 +4433,6 @@ public class MediaPlayer extends PlayerBase } - @NonNull - private native String _getDrmPropertyString(@NonNull String propertyName); - /** * Read a DRM engine plugin String property value, given the property name string. * <p> @@ -4393,26 +4446,29 @@ public class MediaPlayer extends PlayerBase public String getDrmPropertyString(@NonNull @MediaDrm.StringProperty String propertyName) throws NoDrmSchemeException { + Log.v(TAG, "getDrmPropertyString: propertyName: " + propertyName); + String value; synchronized (mDrmLock) { if (!mActiveDrmScheme && !mDrmConfigAllowed) { - Log.w(TAG, String.format("getDrmPropertyString NoDrmSchemeException")); + Log.w(TAG, "getDrmPropertyString NoDrmSchemeException"); throw new NoDrmSchemeException("getDrmPropertyString: Has to prepareDrm() first."); } try { - value = _getDrmPropertyString(propertyName); + value = mDrmObj.getPropertyString(propertyName); } catch (Exception e) { - Log.w(TAG, String.format("getDrmPropertyString Exception %s", e)); + Log.w(TAG, "getDrmPropertyString Exception " + e); throw e; } } // synchronized + Log.v(TAG, "getDrmPropertyString: propertyName: " + propertyName + " --> value: " + value); + return value; } - private native void _setDrmPropertyString(@NonNull String propertyName, @NonNull String value); /** * Set a DRM engine plugin String property value. @@ -4428,17 +4484,19 @@ public class MediaPlayer extends PlayerBase @NonNull String value) throws NoDrmSchemeException { + Log.v(TAG, "setDrmPropertyString: propertyName: " + propertyName + " value: " + value); + synchronized (mDrmLock) { if ( !mActiveDrmScheme && !mDrmConfigAllowed ) { - Log.w(TAG, String.format("setDrmPropertyString NoDrmSchemeException")); + Log.w(TAG, "setDrmPropertyString NoDrmSchemeException"); throw new NoDrmSchemeException("setDrmPropertyString: Has to prepareDrm() first."); } try { - _setDrmPropertyString(propertyName, value); + mDrmObj.setPropertyString(propertyName, value); } catch ( Exception e ) { - Log.w(TAG, String.format("setDrmPropertyString Exception %s", e)); + Log.w(TAG, "setDrmPropertyString Exception " + e); throw e; } } // synchronized @@ -4605,8 +4663,47 @@ public class MediaPlayer extends PlayerBase } } + + private native void _prepareDrm(@NonNull byte[] uuid, @NonNull byte[] drmSessionId); + // Modular DRM helpers + private void prepareDrm_createDrmStep(@NonNull UUID uuid) + throws UnsupportedSchemeException { + Log.v(TAG, "prepareDrm_createDrmStep: UUID: " + uuid); + + try { + mDrmObj = new MediaDrm(uuid); + Log.v(TAG, "prepareDrm_createDrmStep: Created mDrmObj=" + mDrmObj); + } catch (Exception e) { // UnsupportedSchemeException + Log.e(TAG, "prepareDrm_createDrmStep: MediaDrm failed with " + e); + throw e; + } + } + + private void prepareDrm_openSessionStep(@NonNull UUID uuid) + throws NotProvisionedException, ResourceBusyException { + Log.v(TAG, "prepareDrm_openSessionStep: uuid: " + uuid); + + // TODO: don't need an open session for a future specialKeyReleaseDrm mode but we should do + // it anyway so it raises provisioning error if needed. We'd rather handle provisioning + // at prepareDrm/openSession rather than getKeyRequest/provideKeyResponse + try { + mDrmSessionId = mDrmObj.openSession(); + Log.v(TAG, "prepareDrm_openSessionStep: mDrmSessionId=" + mDrmSessionId); + + // Sending it down to native/mediaserver to create the crypto object + // This call could simply fail due to bad player state, e.g., after start(). + _prepareDrm(getByteArrayFromUUID(uuid), mDrmSessionId); + Log.v(TAG, "prepareDrm_openSessionStep: _prepareDrm/Crypto succeeded"); + + } catch (Exception e) { //ResourceBusyException, NotProvisionedException + Log.e(TAG, "prepareDrm_openSessionStep: open/crypto failed with " + e); + throw e; + } + + } + private class ProvisioningThread extends Thread { public static final int TIMEOUT_MS = 60000; @@ -4633,7 +4730,7 @@ public class MediaPlayer extends PlayerBase urlStr = request.getDefaultUrl() + "&signedRequest=" + new String(request.getData()); this.uuid = uuid; - Log.v(TAG, String.format("HandleProvisioninig: Thread is initialised url: %s", urlStr)); + Log.v(TAG, "HandleProvisioninig: Thread is initialised url: " + urlStr); return this; } @@ -4653,30 +4750,27 @@ public class MediaPlayer extends PlayerBase connection.connect(); response = Streams.readFully(connection.getInputStream()); - Log.v(TAG, String.format("HandleProvisioninig: Thread run response %d %s", - response.length, response)); + Log.v(TAG, "HandleProvisioninig: Thread run: response " + + response.length + " " + response); } catch (Exception e) { - Log.w(TAG, String.format("HandleProvisioninig: Thread run connect %s url: %s", - e, url)); + Log.w(TAG, "HandleProvisioninig: Thread run: connect " + e + " url: " + url); } finally { connection.disconnect(); } } catch (Exception e) { - Log.w(TAG, String.format("HandleProvisioninig: Thread run openConnection %s", e)); + Log.w(TAG, "HandleProvisioninig: Thread run: openConnection " + e); } if (response != null) { try { - MediaDrm drm = new MediaDrm(uuid); - drm.provideProvisionResponse(response); - drm.release(); - Log.v(TAG, String.format("HandleProvisioninig: Thread run " + - "newDrm+provideProvisionResponse SUCCEEDED!")); + mDrmObj.provideProvisionResponse(response); + Log.v(TAG, "HandleProvisioninig: Thread run: " + + "provideProvisionResponse SUCCEEDED!"); provisioningSucceeded = true; } catch (Exception e) { - Log.w(TAG, String.format("HandleProvisioninig: Thread run " + - "newDrm+provideProvisionResponse %s", e)); + Log.w(TAG, "HandleProvisioninig: Thread run: " + + "provideProvisionResponse " + e); } } @@ -4690,7 +4784,10 @@ public class MediaPlayer extends PlayerBase } mediaPlayer.mDrmProvisioningInProgress = false; mediaPlayer.mPrepareDrmInProgress = false; - } + if (!succeeded) { + cleanDrmObj(); // cleaning up if it hasn't gone through while in the lock + } + } // synchronized // calling the callback outside the lock onDrmPreparedHandlerDelegate.notifyClient(succeeded); @@ -4702,6 +4799,9 @@ public class MediaPlayer extends PlayerBase } mediaPlayer.mDrmProvisioningInProgress = false; mediaPlayer.mPrepareDrmInProgress = false; + if (!succeeded) { + cleanDrmObj(); // cleaning up if it hasn't gone through + } } finished = true; @@ -4714,24 +4814,18 @@ public class MediaPlayer extends PlayerBase // the lock is already held by the caller if (mDrmProvisioningInProgress) { - Log.e(TAG, String.format("HandleProvisioninig: Unexpected mDrmProvisioningInProgress")); + Log.e(TAG, "HandleProvisioninig: Unexpected mDrmProvisioningInProgress"); return false; } - MediaDrm.ProvisionRequest provReq = null; - try { - MediaDrm drm = new MediaDrm(uuid); - provReq = drm.getProvisionRequest(); - drm.release(); - } catch (Exception e) { - Log.e(TAG, String.format("HandleProvisioninig: getProvisionRequest failed with %s", e)); + MediaDrm.ProvisionRequest provReq = mDrmObj.getProvisionRequest(); + if (provReq == null) { + Log.e(TAG, "HandleProvisioninig: getProvisionRequest returned null."); return false; } - Log.v(TAG, String.format("HandleProvisioninig provReq: data %s url %s", - (provReq != null) ? provReq.getData() : "-", - (provReq != null) ? provReq.getDefaultUrl() : "://") - ); + Log.v(TAG, "HandleProvisioninig provReq " + + " data: " + provReq.getData() + " url: " + provReq.getDefaultUrl()); // networking in a background thread mDrmProvisioningInProgress = true; @@ -4749,7 +4843,7 @@ public class MediaPlayer extends PlayerBase try { mDrmProvisioningThread.join(); } catch (Exception e) { - Log.w(TAG, String.format("HandleProvisioninig: Thread.join Exception %s", e)); + Log.w(TAG, "HandleProvisioninig: Thread.join Exception " + e); } result = mDrmProvisioningThread.succeeded(); // no longer need the thread @@ -4761,19 +4855,21 @@ public class MediaPlayer extends PlayerBase private boolean resumePrepareDrm(UUID uuid) { + Log.v(TAG, "resumePrepareDrm: uuid: " + uuid); + // mDrmLock is guaranteed to be held boolean success = false; try { - boolean allowOpenSession = true; // resuming - _prepareDrm(getByteArrayFromUUID(uuid), allowOpenSession ? 1 : 0); + // resuming + prepareDrm_openSessionStep(uuid); mDrmUUID = uuid; mActiveDrmScheme = true; success = true; } catch (Exception e) { - Log.w(TAG, String.format("HandleProvisioninig: " + - "Thread run _prepareDrm resume failed with %s", e)); + Log.w(TAG, "HandleProvisioninig: Thread run _prepareDrm resume failed with " + e); + // mDrmObj clean up is done by the caller } return success; @@ -4782,6 +4878,12 @@ public class MediaPlayer extends PlayerBase private void resetDrmState() { synchronized (mDrmLock) { + Log.v(TAG, "resetDrmState: " + + " mDrmInfo=" + mDrmInfo + + " mDrmProvisioningThread=" + mDrmProvisioningThread + + " mPrepareDrmInProgress=" + mPrepareDrmInProgress + + " mActiveDrmScheme=" + mActiveDrmScheme); + mDrmInfoResolved = false; mDrmInfo = null; @@ -4791,15 +4893,33 @@ public class MediaPlayer extends PlayerBase mDrmProvisioningThread.join(); } catch (InterruptedException e) { - Log.w(TAG, String.format("resetDrmState: ProvThread.join Exception %s", e)); + Log.w(TAG, "resetDrmState: ProvThread.join Exception " + e); } mDrmProvisioningThread = null; } mPrepareDrmInProgress = false; + mActiveDrmScheme = false; + + cleanDrmObj(); } // synchronized } + private void cleanDrmObj() + { + // the caller holds mDrmLock + Log.v(TAG, "cleanDrmObj: mDrmObj=" + mDrmObj + " mDrmSessionId=" + mDrmSessionId); + + if (mDrmSessionId != null) { + mDrmObj.closeSession(mDrmSessionId); + mDrmSessionId = null; + } + if (mDrmObj != null) { + mDrmObj.release(); + mDrmObj = null; + } + } + private static final byte[] getByteArrayFromUUID(@NonNull UUID uuid) { long msb = uuid.getMostSignificantBits(); long lsb = uuid.getLeastSignificantBits(); diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index c941766c07d6..636727eb0ac0 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -58,86 +58,20 @@ #include "android_util_Binder.h" // Modular DRM begin -#include <media/drm/DrmAPI.h> - #define FIND_CLASS(var, className) \ var = env->FindClass(className); \ LOG_FATAL_IF(! (var), "Unable to find class " className); -#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ -var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \ -LOG_FATAL_IF(! (var), "Unable to find field " fieldName); - #define GET_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \ var = env->GetMethodID(clazz, fieldName, fieldDescriptor); \ LOG_FATAL_IF(! (var), "Unable to find method " fieldName); -#define GET_STATIC_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \ -var = env->GetStaticFieldID(clazz, fieldName, fieldDescriptor); \ -LOG_FATAL_IF(! (var), "Unable to find field " fieldName); - - -// TODO: investigate if these can be shared with their MediaDrm counterparts -struct RequestFields { - jfieldID data; - jfieldID defaultUrl; - jfieldID requestType; -}; - -struct HashmapFields { - jmethodID init; - jmethodID get; - jmethodID put; - jmethodID entrySet; -}; - -struct SetFields { - jmethodID iterator; -}; - -struct IteratorFields { - jmethodID next; - jmethodID hasNext; -}; - -struct EntryFields { - jmethodID getKey; - jmethodID getValue; -}; - -struct KeyTypes { - jint kKeyTypeStreaming; - jint kKeyTypeOffline; - jint kKeyTypeRelease; -}; - -static KeyTypes gKeyTypes; - -struct KeyRequestTypes { - jint kKeyRequestTypeInitial; - jint kKeyRequestTypeRenewal; - jint kKeyRequestTypeRelease; -}; - -static KeyRequestTypes gKeyRequestTypes; - struct StateExceptionFields { jmethodID init; jclass classId; }; -struct drm_fields_t { - RequestFields keyRequest; - HashmapFields hashmap; - SetFields set; - IteratorFields iterator; - EntryFields entry; - StateExceptionFields stateException; - jclass stringClassId; -}; - -static drm_fields_t gFields; - +static StateExceptionFields gStateExceptionFields; // Modular DRM end // ---------------------------------------------------------------------------- @@ -1041,50 +975,14 @@ android_media_MediaPlayer_native_init(JNIEnv *env) gBufferingParamsFields.init(env); // Modular DRM - FIND_CLASS(clazz, "android/media/MediaDrm"); - if (clazz) { - jfieldID field; - GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I"); - gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field); - GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I"); - gKeyTypes.kKeyTypeOffline = env->GetStaticIntField(clazz, field); - GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_RELEASE", "I"); - gKeyTypes.kKeyTypeRelease = env->GetStaticIntField(clazz, field); - - env->DeleteLocalRef(clazz); - } else { - ALOGE("JNI getKeyRequest android_media_MediaPlayer_native_init couldn't " - "get clazz android/media/MediaDrm"); - } - - FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest"); - if (clazz) { - GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B"); - GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;"); - GET_FIELD_ID(gFields.keyRequest.requestType, clazz, "mRequestType", "I"); - - jfieldID field; - GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_INITIAL", "I"); - gKeyRequestTypes.kKeyRequestTypeInitial = env->GetStaticIntField(clazz, field); - GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RENEWAL", "I"); - gKeyRequestTypes.kKeyRequestTypeRenewal = env->GetStaticIntField(clazz, field); - GET_STATIC_FIELD_ID(field, clazz, "REQUEST_TYPE_RELEASE", "I"); - gKeyRequestTypes.kKeyRequestTypeRelease = env->GetStaticIntField(clazz, field); - - env->DeleteLocalRef(clazz); - } else { - ALOGE("JNI getKeyRequest android_media_MediaPlayer_native_init couldn't " - "get clazz android/media/MediaDrm$KeyRequest"); - } - FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException"); if (clazz) { - GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(ILjava/lang/String;)V"); - gFields.stateException.classId = static_cast<jclass>(env->NewGlobalRef(clazz)); + GET_METHOD_ID(gStateExceptionFields.init, clazz, "<init>", "(ILjava/lang/String;)V"); + gStateExceptionFields.classId = static_cast<jclass>(env->NewGlobalRef(clazz)); env->DeleteLocalRef(clazz); } else { - ALOGE("JNI getKeyRequest android_media_MediaPlayer_native_init couldn't " + ALOGE("JNI android_media_MediaPlayer_native_init couldn't " "get clazz android/media/MediaDrm$MediaDrmStateException"); } @@ -1315,8 +1213,8 @@ static void throwDrmStateException(JNIEnv *env, const char *msg, status_t err) { ALOGE("Illegal DRM state exception: %s (%d)", msg, err); - jobject exception = env->NewObject(gFields.stateException.classId, - gFields.stateException.init, static_cast<int>(err), + jobject exception = env->NewObject(gStateExceptionFields.classId, + gStateExceptionFields.init, static_cast<int>(err), env->NewStringUTF(msg)); env->Throw(static_cast<jthrowable>(exception)); } @@ -1393,18 +1291,6 @@ static bool throwDrmExceptionAsNecessary(JNIEnv *env, status_t err, const char * return false; } -// TODO: investigate if these can be shared with their MediaDrm counterparts -static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) -{ - size_t length = vector.size(); - jbyteArray result = env->NewByteArray(length); - if (result != NULL) { - env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array()); - } - return result; -} - -// TODO: investigate if these can be shared with their MediaDrm counterparts static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) { Vector<uint8_t> vector; @@ -1414,74 +1300,8 @@ static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArr return vector; } -// TODO: investigate if these can be shared with their MediaDrm counterparts -static String8 JStringToString8(JNIEnv *env, jstring const &jstr) -{ - String8 result; - - const char *s = env->GetStringUTFChars(jstr, NULL); - if (s) { - result = s; - env->ReleaseStringUTFChars(jstr, s); - } - return result; -} - -// TODO: investigate if these can be shared with their MediaDrm counterparts -static KeyedVector<String8, String8> HashMapToKeyedVector(JNIEnv *env, - jobject &hashMap, bool* pIsOK) -{ - jclass clazz = gFields.stringClassId; - KeyedVector<String8, String8> keyedVector; - *pIsOK = true; - - jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet); - if (entrySet) { - jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator); - if (iterator) { - jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext); - while (hasNext) { - jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next); - if (entry) { - jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey); - if (obj == NULL || !env->IsInstanceOf(obj, clazz)) { - jniThrowException(env, "java/lang/IllegalArgumentException", - "HashMap key is not a String"); - env->DeleteLocalRef(entry); - *pIsOK = false; - break; - } - jstring jkey = static_cast<jstring>(obj); - - obj = env->CallObjectMethod(entry, gFields.entry.getValue); - if (obj == NULL || !env->IsInstanceOf(obj, clazz)) { - jniThrowException(env, "java/lang/IllegalArgumentException", - "HashMap value is not a String"); - env->DeleteLocalRef(entry); - *pIsOK = false; - break; - } - jstring jvalue = static_cast<jstring>(obj); - - String8 key = JStringToString8(env, jkey); - String8 value = JStringToString8(env, jvalue); - keyedVector.add(key, value); - - env->DeleteLocalRef(jkey); - env->DeleteLocalRef(jvalue); - hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext); - } - env->DeleteLocalRef(entry); - } - env->DeleteLocalRef(iterator); - } - env->DeleteLocalRef(entrySet); - } - return keyedVector; -} - static void android_media_MediaPlayer_prepareDrm(JNIEnv *env, jobject thiz, - jbyteArray uuidObj, jint mode) + jbyteArray uuidObj, jbyteArray drmSessionIdObj) { sp<MediaPlayer> mp = getMediaPlayer(env, thiz); if (mp == NULL) { @@ -1504,13 +1324,23 @@ static void android_media_MediaPlayer_prepareDrm(JNIEnv *env, jobject thiz, return; } - status_t err = mp->prepareDrm(uuid.array(), mode); + Vector<uint8_t> drmSessionId = JByteArrayToVector(env, drmSessionIdObj); + + if (drmSessionId.size() == 0) { + jniThrowException( + env, + "java/lang/IllegalArgumentException", + "empty drmSessionId"); + return; + } + + status_t err = mp->prepareDrm(uuid.array(), drmSessionId); if (err != OK) { if (err == INVALID_OPERATION) { jniThrowException( env, "java/lang/IllegalStateException", - "The player is not prepared yet."); + "The player must be in prepared state."); } else if (err == ERROR_DRM_CANNOT_HANDLE) { jniThrowException( env, @@ -1536,210 +1366,9 @@ static void android_media_MediaPlayer_releaseDrm(JNIEnv *env, jobject thiz) jniThrowException( env, "java/lang/IllegalStateException", - "The player is not prepared yet."); - } - } -} - -static jobject android_media_MediaPlayer_getKeyRequest(JNIEnv *env, jobject thiz, jbyteArray jscope, - jstring jmimeType, jint jkeyType, jobject joptParams) -{ - sp<MediaPlayer> mp = getMediaPlayer(env, thiz); - if (mp == NULL) { - jniThrowException(env, "java/lang/IllegalStateException", NULL); - return NULL; - } - - Vector<uint8_t> scope; - if (jscope != NULL) { - scope = JByteArrayToVector(env, jscope); - } - - String8 mimeType; - if (jmimeType != NULL) { - mimeType = JStringToString8(env, jmimeType); - } - - DrmPlugin::KeyType keyType; - if (jkeyType == gKeyTypes.kKeyTypeStreaming) { - keyType = DrmPlugin::kKeyType_Streaming; - } else if (jkeyType == gKeyTypes.kKeyTypeOffline) { - keyType = DrmPlugin::kKeyType_Offline; - } else if (jkeyType == gKeyTypes.kKeyTypeRelease) { - keyType = DrmPlugin::kKeyType_Release; - } else { - jniThrowException(env, "java/lang/IllegalArgumentException", "invalid keyType"); - return NULL; - } - - KeyedVector<String8, String8> optParams; - if (joptParams != NULL) { - bool isOK; - optParams = HashMapToKeyedVector(env, joptParams, &isOK); - if (!isOK) { - return NULL; - } - } - - Vector<uint8_t> request; - String8 defaultUrl; - DrmPlugin::KeyRequestType keyRequestType; - status_t err = mp->getKeyRequest(scope, mimeType, keyType, optParams, request, defaultUrl, - keyRequestType); - - if (throwDrmExceptionAsNecessary(env, err, "Failed to get key request")) { - return NULL; - } - - ALOGV("JNI getKeyRequest err %d request %d url %s keyReqType %d", - err, (int)request.size(), defaultUrl.string(), (int)keyRequestType); - - // Fill out return obj - jclass clazz; - FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest"); - - jobject keyObj = NULL; - - if (clazz) { - keyObj = env->AllocObject(clazz); - jbyteArray jrequest = VectorToJByteArray(env, request); - env->SetObjectField(keyObj, gFields.keyRequest.data, jrequest); - - jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string()); - env->SetObjectField(keyObj, gFields.keyRequest.defaultUrl, jdefaultUrl); - - switch (keyRequestType) { - case DrmPlugin::kKeyRequestType_Initial: - env->SetIntField(keyObj, gFields.keyRequest.requestType, - gKeyRequestTypes.kKeyRequestTypeInitial); - break; - case DrmPlugin::kKeyRequestType_Renewal: - env->SetIntField(keyObj, gFields.keyRequest.requestType, - gKeyRequestTypes.kKeyRequestTypeRenewal); - break; - case DrmPlugin::kKeyRequestType_Release: - env->SetIntField(keyObj, gFields.keyRequest.requestType, - gKeyRequestTypes.kKeyRequestTypeRelease); - break; - default: - throwDrmStateException(env, "MediaPlayer/DRM plugin failure: unknown " - "key request type", ERROR_DRM_UNKNOWN); - break; + "Can not release DRM in an active player state."); } } - - return keyObj; -} - -static jbyteArray android_media_MediaPlayer_provideKeyResponse(JNIEnv *env, jobject thiz, - jbyteArray jreleaseKeySetId, jbyteArray jresponse) -{ - sp<MediaPlayer> mp = getMediaPlayer(env, thiz); - if (mp == NULL ) { - jniThrowException(env, "java/lang/IllegalStateException", NULL); - return NULL; - } - - if (jresponse == NULL) { - jniThrowException(env, "java/lang/IllegalArgumentException", "key response is null"); - return NULL; - } - - Vector<uint8_t> releaseKeySetId; - if (jreleaseKeySetId != NULL) { - releaseKeySetId = JByteArrayToVector(env, jreleaseKeySetId); - } - - Vector<uint8_t> response(JByteArrayToVector(env, jresponse)); - Vector<uint8_t> keySetId; - - status_t err = mp->provideKeyResponse(releaseKeySetId, response, keySetId); - - if (throwDrmExceptionAsNecessary(env, err, "Failed to handle key response")) { - return NULL; - } - return VectorToJByteArray(env, keySetId); -} - -static void android_media_MediaPlayer_restoreKeys(JNIEnv *env, jobject thiz, jbyteArray jkeySetId) -{ - sp<MediaPlayer> mp = getMediaPlayer(env, thiz); - if (mp == NULL) { - jniThrowException(env, "java/lang/IllegalStateException", NULL); - return; - } - - if (jkeySetId == NULL) { - jniThrowException(env, "java/lang/IllegalArgumentException", "invalid keyType"); - return; - } - - Vector<uint8_t> keySetId; - keySetId = JByteArrayToVector(env, jkeySetId); - - status_t err = mp->restoreKeys(keySetId); - - ALOGV("JNI restoreKeys err %d ", err); - throwDrmExceptionAsNecessary(env, err, "Failed to restore keys"); -} - -static jstring android_media_MediaPlayer_getDrmPropertyString(JNIEnv *env, jobject thiz, - jstring jname) -{ - sp<MediaPlayer> mp = getMediaPlayer(env, thiz); - if (mp == NULL) { - jniThrowException(env, "java/lang/IllegalStateException", NULL); - return NULL; - } - - if (jname == NULL) { - jniThrowException(env, "java/lang/IllegalArgumentException", - "property name String is null"); - return NULL; - } - - String8 name = JStringToString8(env, jname); - String8 value; - - status_t err = mp->getDrmPropertyString(name, value); - - ALOGV("JNI getPropertyString err %d", err); - - if (throwDrmExceptionAsNecessary(env, err, "Failed to get property")) { - return NULL; - } - - return env->NewStringUTF(value.string()); -} - -static void android_media_MediaPlayer_setDrmPropertyString(JNIEnv *env, jobject thiz, - jstring jname, jstring jvalue) -{ - sp<MediaPlayer> mp = getMediaPlayer(env, thiz); - if (mp == NULL) { - jniThrowException(env, "java/lang/IllegalStateException", NULL); - return; - } - - if (jname == NULL) { - jniThrowException(env, "java/lang/IllegalArgumentException", - "property name String is null"); - return; - } - - if (jvalue == NULL) { - jniThrowException(env, "java/lang/IllegalArgumentException", - "property value String is null"); - return; - } - - String8 name = JStringToString8(env, jname); - String8 value = JStringToString8(env, jvalue); - - status_t err = mp->setDrmPropertyString(name, value); - - ALOGV("JNI setPropertyString err %d", err); - throwDrmExceptionAsNecessary(env, err, "Failed to set property"); } // Modular DRM end // ---------------------------------------------------------------------------- @@ -1802,14 +1431,8 @@ static const JNINativeMethod gMethods[] = { "(I)Landroid/media/VolumeShaper$State;", (void *)android_media_MediaPlayer_getVolumeShaperState}, // Modular DRM - { "_prepareDrm", "([BI)V", (void *)android_media_MediaPlayer_prepareDrm }, + { "_prepareDrm", "([B[B)V", (void *)android_media_MediaPlayer_prepareDrm }, { "_releaseDrm", "()V", (void *)android_media_MediaPlayer_releaseDrm }, - { "_getKeyRequest", "([BLjava/lang/String;ILjava/util/Map;)" "Landroid/media/MediaDrm$KeyRequest;", - (void *)android_media_MediaPlayer_getKeyRequest }, - { "_provideKeyResponse", "([B[B)[B", (void *)android_media_MediaPlayer_provideKeyResponse }, - { "_getDrmPropertyString", "(Ljava/lang/String;)Ljava/lang/String;", (void *)android_media_MediaPlayer_getDrmPropertyString }, - { "_setDrmPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",(void *)android_media_MediaPlayer_setDrmPropertyString }, - { "_restoreKeys", "([B)V", (void *)android_media_MediaPlayer_restoreKeys }, }; // This function only registers the native methods diff --git a/obex/javax/obex/ServerSession.java b/obex/javax/obex/ServerSession.java index acee5ddd5f8f..3831cf7285da 100644 --- a/obex/javax/obex/ServerSession.java +++ b/obex/javax/obex/ServerSession.java @@ -658,6 +658,11 @@ public final class ServerSession extends ObexSession implements Runnable { */ byte[] sendData = new byte[totalLength]; int maxRxLength = ObexHelper.getMaxRxPacketSize(mTransport); + if (maxRxLength > mMaxPacketLength) { + if(V) Log.v(TAG,"Set maxRxLength to min of maxRxServrLen:" + maxRxLength + + " and MaxNegotiated from Client: " + mMaxPacketLength); + maxRxLength = mMaxPacketLength; + } sendData[0] = (byte)code; sendData[1] = length[2]; sendData[2] = length[3]; diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java index 8a970da474e6..25127efad502 100644 --- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java +++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java @@ -33,7 +33,6 @@ import android.view.View; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; -import android.widget.Toast; public class DeviceChooserActivity extends Activity { @@ -129,12 +128,9 @@ public class DeviceChooserActivity extends Activity { } protected void onPairTapped(BluetoothDevice selectedDevice) { + getService().onDeviceSelected(); setResult(RESULT_OK, new Intent().putExtra(CompanionDeviceManager.EXTRA_DEVICE, selectedDevice)); finish(); } - - private void toast(String msg) { - Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); - } }
\ No newline at end of file diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java index ccbee2ae196e..11c722d7676c 100644 --- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java +++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java @@ -32,16 +32,15 @@ import android.bluetooth.le.ScanFilter; import android.bluetooth.le.ScanResult; import android.bluetooth.le.ScanSettings; import android.companion.AssociationRequest; -import android.companion.BluetoothDeviceFilterUtils; import android.companion.BluetoothLEDeviceFilter; -import android.companion.ICompanionDeviceManagerService; -import android.companion.IOnAssociateCallback; +import android.companion.ICompanionDeviceDiscoveryService; +import android.companion.ICompanionDeviceDiscoveryServiceCallback; +import android.companion.IFindDeviceCallback; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Color; -import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; import android.os.IBinder; import android.os.RemoteException; @@ -70,21 +69,25 @@ public class DeviceDiscoveryService extends Service { List<BluetoothDevice> mDevicesFound; BluetoothDevice mSelectedDevice; DevicesAdapter mDevicesAdapter; - IOnAssociateCallback mCallback; + IFindDeviceCallback mFindCallback; + ICompanionDeviceDiscoveryServiceCallback mServiceCallback; String mCallingPackage; - private final ICompanionDeviceManagerService mBinder = - new ICompanionDeviceManagerService.Stub() { + private final ICompanionDeviceDiscoveryService mBinder = + new ICompanionDeviceDiscoveryService.Stub() { @Override public void startDiscovery(AssociationRequest request, - IOnAssociateCallback callback, - String callingPackage) throws RemoteException { + String callingPackage, + IFindDeviceCallback findCallback, + ICompanionDeviceDiscoveryServiceCallback serviceCallback) { if (DEBUG) { Log.i(LOG_TAG, - "startDiscovery() called with: filter = [" + request + "], callback = [" - + callback + "]"); + "startDiscovery() called with: filter = [" + request + + "], findCallback = [" + findCallback + "]" + + "], serviceCallback = [" + serviceCallback + "]"); } - mCallback = callback; + mFindCallback = findCallback; + mServiceCallback = serviceCallback; mCallingPackage = callingPackage; DeviceDiscoveryService.this.startDiscovery(request); } @@ -171,6 +174,14 @@ public class DeviceDiscoveryService extends Service { return super.onUnbind(intent); } + public void onDeviceSelected() { + try { + mServiceCallback.onDeviceSelected(mCallingPackage, getUserId()); + } catch (RemoteException e) { + Log.e(LOG_TAG, "Error reporting selected device"); + } + } + private void stopScan() { if (DEBUG) Log.i(LOG_TAG, "stopScan() called"); mBluetoothAdapter.cancelDiscovery(); @@ -205,7 +216,7 @@ public class DeviceDiscoveryService extends Service { //TODO also, on timeout -> call onFailure private void onReadyToShowUI() { try { - mCallback.onSuccess(PendingIntent.getActivity( + mFindCallback.onSuccess(PendingIntent.getActivity( this, 0, new Intent(this, DeviceChooserActivity.class), PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java index 0ec16ae26843..9ac4d2de6c59 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java @@ -510,7 +510,7 @@ public class WifiTracker { } NetworkKey key = NetworkKey.createFromScanResult(result); - if (!mRequestedScores.contains(key)) { + if (key != null && !mRequestedScores.contains(key)) { scoresToRequest.add(key); } diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml index 499b6ae0f5d3..136f17e5a77c 100644 --- a/packages/SettingsProvider/res/values/defaults.xml +++ b/packages/SettingsProvider/res/values/defaults.xml @@ -227,7 +227,4 @@ <!-- default setting for Settings.System.END_BUTTON_BEHAVIOR : END_BUTTON_BEHAVIOR_SLEEP --> <integer name="def_end_button_behavior">0x2</integer> - - <!--Default settings for network recommendations. --> - <string name="def_network_recommendations_package" translatable="false">com.android.networkrecommendation</string> </resources> diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index edcb9b51fceb..d5787e6482b5 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -3182,24 +3182,7 @@ public class SettingsProvider extends ContentProvider { } if (currentVersion == 138) { - // Version 139: Applying the default to NETWORK_RECOMMENDATIONS_PACKAGE - if (userId == UserHandle.USER_SYSTEM) { - final SettingsState globalSettings = getGlobalSettingsLocked(); - final String defaultAppPackage = getContext().getResources() - .getString(R.string.def_network_recommendations_package); - - // Set the network recommendations package name - globalSettings.insertSettingLocked( - Global.NETWORK_RECOMMENDATIONS_PACKAGE, - defaultAppPackage, null, true, - SettingsState.SYSTEM_PACKAGE_NAME); - - // Clear the scorer setting since it's no longer needed. - globalSettings.insertSettingLocked( - Global.NETWORK_SCORER_APP, - null, null, true, - SettingsState.SYSTEM_PACKAGE_NAME); - } + // Version 139: Removed. currentVersion = 139; } diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index d4c7c7ad8cb1..2e115abaf67d 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -154,8 +154,8 @@ android:name=".BugreportReceiver" android:permission="android.permission.DUMP"> <intent-filter> - <action android:name="android.intent.action.BUGREPORT_STARTED" /> - <action android:name="android.intent.action.BUGREPORT_FINISHED" /> + <action android:name="com.android.internal.intent.action.BUGREPORT_STARTED" /> + <action android:name="com.android.internal.intent.action.BUGREPORT_FINISHED" /> </intent-filter> </receiver> @@ -163,7 +163,7 @@ android:name=".RemoteBugreportReceiver" android:permission="android.permission.DUMP"> <intent-filter> - <action android:name="android.intent.action.REMOTE_BUGREPORT_FINISHED" /> + <action android:name="com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED" /> </intent-filter> </receiver> diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java index 17d0a09d8154..12d0c0306e61 100644 --- a/packages/Shell/src/com/android/shell/BugreportProgressService.java +++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java @@ -133,10 +133,12 @@ public class BugreportProgressService extends Service { private static final String AUTHORITY = "com.android.shell"; // External intents sent by dumpstate. - static final String INTENT_BUGREPORT_STARTED = "android.intent.action.BUGREPORT_STARTED"; - static final String INTENT_BUGREPORT_FINISHED = "android.intent.action.BUGREPORT_FINISHED"; + static final String INTENT_BUGREPORT_STARTED = + "com.android.internal.intent.action.BUGREPORT_STARTED"; + static final String INTENT_BUGREPORT_FINISHED = + "com.android.internal.intent.action.BUGREPORT_FINISHED"; static final String INTENT_REMOTE_BUGREPORT_FINISHED = - "android.intent.action.REMOTE_BUGREPORT_FINISHED"; + "com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED"; // Internal intents used on notification actions. static final String INTENT_BUGREPORT_CANCEL = "android.intent.action.BUGREPORT_CANCEL"; diff --git a/packages/SystemUI/res/drawable/ic_data_saver.xml b/packages/SystemUI/res/drawable/ic_data_saver.xml index 9c3bd3a7f374..64bbff02cbbc 100644 --- a/packages/SystemUI/res/drawable/ic_data_saver.xml +++ b/packages/SystemUI/res/drawable/ic_data_saver.xml @@ -23,7 +23,7 @@ android:fillColor="#FFFFFFFF" android:pathData="M12.0,19.0c-3.9,0.0 -7.0,-3.1 -7.0,-7.0c0.0,-3.5 2.6,-6.4 6.0,-6.9L11.0,2.0C5.9,2.5 2.0,6.8 2.0,12.0c0.0,5.5 4.5,10.0 10.0,10.0c3.3,0.0 6.2,-1.6 8.1,-4.1l-2.6,-1.5C16.2,18.0 14.2,19.0 12.0,19.0z"/> <path - android:fillColor="#4DFFFFFF" + android:fillColor="#54FFFFFF" android:pathData="M13.0,2.0l0.0,3.0c3.4,0.5 6.0,3.4 6.0,6.9c0.0,0.9 -0.2,1.8 -0.5,2.5l2.6,1.5c0.6,-1.2 0.9,-2.6 0.9,-4.1C22.0,6.8 18.0,2.6 13.0,2.0z"/> <path android:fillColor="#FFFFFFFF" diff --git a/packages/SystemUI/res/drawable/ic_data_saver_off.xml b/packages/SystemUI/res/drawable/ic_data_saver_off.xml index 918c61c3fc39..3001ad9fa7be 100644 --- a/packages/SystemUI/res/drawable/ic_data_saver_off.xml +++ b/packages/SystemUI/res/drawable/ic_data_saver_off.xml @@ -20,9 +20,9 @@ android:viewportHeight="24.0" android:tint="?android:attr/colorControlNormal"> <path - android:fillColor="#4DFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M12.0,19.0c-3.9,0.0 -7.0,-3.1 -7.0,-7.0c0.0,-3.5 2.6,-6.4 6.0,-6.9L11.0,2.0C5.9,2.5 2.0,6.8 2.0,12.0c0.0,5.5 4.5,10.0 10.0,10.0c3.3,0.0 6.2,-1.6 8.1,-4.1l-2.6,-1.5C16.2,18.0 14.2,19.0 12.0,19.0z"/> <path - android:fillColor="#4DFFFFFF" + android:fillColor="#FFFFFFFF" android:pathData="M13.0,2.0l0.0,3.0c3.4,0.5 6.0,3.4 6.0,6.9c0.0,0.9 -0.2,1.8 -0.5,2.5l2.6,1.5c0.6,-1.2 0.9,-2.6 0.9,-4.1C22.0,6.8 18.0,2.6 13.0,2.0z"/> </vector> diff --git a/packages/SystemUI/res/layout/battery_percentage_view.xml b/packages/SystemUI/res/layout/battery_percentage_view.xml index d6abc47c5af3..acae9f51c142 100644 --- a/packages/SystemUI/res/layout/battery_percentage_view.xml +++ b/packages/SystemUI/res/layout/battery_percentage_view.xml @@ -25,5 +25,5 @@ android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock" android:textColor="?android:attr/textColorPrimary" android:gravity="center_vertical|start" - android:paddingEnd="4dp" + android:paddingStart="4dp" /> diff --git a/packages/SystemUI/res/layout/divider.xml b/packages/SystemUI/res/layout/divider.xml index 95814371ed56..f1f0df054240 100644 --- a/packages/SystemUI/res/layout/divider.xml +++ b/packages/SystemUI/res/layout/divider.xml @@ -16,5 +16,6 @@ <View xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="72dp" android:layout_height="1dp" + android:layout_marginTop="8dp" android:background="?android:attr/colorForeground" android:alpha="?android:attr/disabledAlpha" /> diff --git a/packages/SystemUI/res/layout/qs_page_indicator.xml b/packages/SystemUI/res/layout/qs_page_indicator.xml index 02bd31a4c972..583753a362f1 100644 --- a/packages/SystemUI/res/layout/qs_page_indicator.xml +++ b/packages/SystemUI/res/layout/qs_page_indicator.xml @@ -20,9 +20,8 @@ android:layout_width="match_parent" android:layout_height="48dp" android:layout_gravity="center" - android:layout_marginTop="40dp" android:layout_marginBottom="24dp" android:focusable="true" android:gravity="center" android:importantForAccessibility="yes" - android:visibility="gone"/>
\ No newline at end of file + android:visibility="gone"/> diff --git a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml index 8ff1d1e3ba18..00427cb1c428 100644 --- a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml +++ b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml @@ -19,6 +19,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" + android:paddingBottom="24dp" android:clipChildren="false" android:clipToPadding="false"> diff --git a/packages/SystemUI/res/layout/qs_tile_label.xml b/packages/SystemUI/res/layout/qs_tile_label.xml index a093b8734dbb..8d1f9e4131f9 100644 --- a/packages/SystemUI/res/layout/qs_tile_label.xml +++ b/packages/SystemUI/res/layout/qs_tile_label.xml @@ -16,10 +16,12 @@ --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="wrap_content" + android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" - android:paddingTop="16dp"> + android:gravity="center_horizontal" + android:paddingTop="8dp" + android:paddingBottom="8dp"> <TextView android:id="@+id/tile_label" android:layout_width="wrap_content" android:layout_height="wrap_content" diff --git a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml index 6988c765cf96..080f553e123e 100644 --- a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml +++ b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml @@ -17,7 +17,6 @@ xmlns:systemui="http://schemas.android.com/apk/res-auto" android:layout_height="48dp" android:layout_width="match_parent" - android:layout_marginBottom="24dp" android:paddingLeft="16dp" android:paddingRight="16dp" style="@style/BrightnessDialogContainer"> diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml index 3e8e72a3d100..78d4bdd6c9dc 100644 --- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml +++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml @@ -85,16 +85,6 @@ <include layout="@layout/system_icons" /> </FrameLayout> - - <TextView - android:id="@+id/battery_level" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - android:layout_marginStart="@dimen/header_battery_margin_expanded" - android:importantForAccessibility="noHideDescendants" - android:textColor="?android:attr/textColorPrimary" - android:textSize="@dimen/battery_level_text_size"/> </LinearLayout> <com.android.systemui.statusbar.AlphaOptimizedFrameLayout diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 2102e0712015..40d4d6f1a843 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -219,8 +219,8 @@ <!-- The size of the gesture span needed to activate the "pull" notification expansion --> <dimen name="pull_span_min">25dp</dimen> - <dimen name="qs_tile_height">80dp</dimen> - <dimen name="qs_tile_margin">36dp</dimen> + <dimen name="qs_tile_height">88dp</dimen> + <dimen name="qs_tile_margin">28dp</dimen> <dimen name="qs_tile_margin_top">16dp</dimen> <dimen name="qs_quick_tile_size">48dp</dimen> <dimen name="qs_quick_tile_padding">12dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 77de9a2c995c..b825cfb5f903 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1725,6 +1725,10 @@ not appear on production builds ever. --> <string name="tuner_doze" translatable="false">Ambient Display</string> + <!-- Ambient display, Sensors wake up device of the tuner. Non-translatable since it should + not appear on production builds ever. --> + <string name="tuner_doze_sensors_wake_up_fully" translatable="false">Wake up device on double tap or lift</string> + <!-- Ambient display always-on of the tuner. Non-translatable since it should not appear on production builds ever. --> <string name="tuner_doze_always_on" translatable="false">Always on</string> @@ -1741,18 +1745,6 @@ <!-- Label for PIP the drag to close zone [CHAR LIMIT=NONE]--> <string name="pip_phone_close">Close</string> - <!-- PIP section of the tuner. Non-translatable since it should - not appear on production builds ever. --> - <string name="picture_in_picture" translatable="false">Picture-in-Picture</string> - - <!-- PIP drag to dismiss title. Non-translatable since it should - not appear on production builds ever. --> - <string name="pip_drag_to_dismiss_title" translatable="false">Drag to dismiss</string> - - <!-- PIP drag to dismiss description. Non-translatable since it should - not appear on production builds ever. --> - <string name="pip_drag_to_dismiss_summary" translatable="false">Drag to the dismiss target at the bottom of the screen to close the PIP</string> - <!-- Tuner string --> <string name="change_theme_reboot" translatable="false">Changing the theme requires a restart.</string> <!-- Tuner string --> diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml index c35481180075..85f12b5baabb 100644 --- a/packages/SystemUI/res/xml/tuner_prefs.xml +++ b/packages/SystemUI/res/xml/tuner_prefs.xml @@ -123,18 +123,6 @@ <!-- <PreferenceScreen - android:key="picture_in_picture" - android:title="@string/picture_in_picture"> - - <com.android.systemui.tuner.TunerSwitch - android:key="pip_drag_to_dismiss" - android:title="@string/pip_drag_to_dismiss_title" - android:summary="@string/pip_drag_to_dismiss_summary" - sysui:defValue="false" /> - - </PreferenceScreen> - - <PreferenceScreen android:key="doze" android:title="@string/tuner_doze"> @@ -143,6 +131,11 @@ android:title="@string/tuner_doze_always_on" sysui:defValue="false" /> + <com.android.systemui.tuner.TunerSwitch + android:key="doze_sensors_wake_up_fully" + android:title="@string/tuner_doze_sensors_wake_up_fully" + sysui:defValue="false" /> + </PreferenceScreen> --> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 80d4a264cac8..1f58d4c55d1d 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -595,6 +595,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } } + public boolean isScreenOn() { + return mScreenOn; + } + static class DisplayClientState { public int clientGeneration; public boolean clearing; diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java index f82130868554..bda4c957c5e8 100644 --- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java +++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java @@ -65,6 +65,7 @@ public class BatteryMeterView extends LinearLayout implements private SettingObserver mSettingObserver; private int mTextColor; private int mLevel; + private boolean mForceShowPercent; public BatteryMeterView(Context context) { this(context, null, 0); @@ -103,6 +104,11 @@ public class BatteryMeterView extends LinearLayout implements updateShowPercent(); } + public void forceShowPercent() { + mForceShowPercent = true; + updateShowPercent(); + } + // StatusBarIconController reaches in here and adjusts the layout parameters of the icon public ImageView getBatteryIconView() { return mBatteryIconView; @@ -173,13 +179,12 @@ public class BatteryMeterView extends LinearLayout implements private void updateShowPercent() { final boolean showing = mBatteryPercentView != null; if (0 != Settings.System.getInt(getContext().getContentResolver(), - BatteryMeterView.SHOW_PERCENT_SETTING, 0)) { + BatteryMeterView.SHOW_PERCENT_SETTING, 0) || mForceShowPercent) { if (!showing) { mBatteryPercentView = loadPercentView(); if (mTextColor != 0) mBatteryPercentView.setTextColor(mTextColor); updatePercentText(); addView(mBatteryPercentView, - 0, new ViewGroup.LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT)); diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java index 19ae2954bb2a..b9ae585c339c 100644 --- a/packages/SystemUI/src/com/android/systemui/Prefs.java +++ b/packages/SystemUI/src/com/android/systemui/Prefs.java @@ -49,6 +49,7 @@ public final class Prefs { Key.QS_WORK_ADDED, }) public @interface Key { + @Deprecated String OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME = "OverviewLastStackTaskActiveTime"; String DEBUG_MODE_ENABLED = "debugModeEnabled"; String HOTSPOT_TILE_LAST_USED = "HotspotTileLastUsed"; diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java index 7c15096a5f9a..b3a0eb7baa72 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java @@ -91,8 +91,7 @@ public class DozeFactory { @Override public void requestState(DozeProvider.DozeState state) { if (state == DozeProvider.DozeState.WAKE_UP) { - PowerManager pm = context.getSystemService(PowerManager.class); - pm.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:NODOZE"); + machine.wakeUp(); return; } machine.requestState(implState(state)); diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java index 6a868d53d409..c9eb790c695e 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java @@ -158,6 +158,11 @@ public class DozeMachine { return mState; } + /** Requests the PowerManager to wake up now. */ + public void wakeUp() { + mDozeService.requestWakeUp(); + } + private boolean isExecutingTransition() { return !mQueuedRequests.isEmpty(); } @@ -300,5 +305,8 @@ public class DozeMachine { /** Request a display state. See {@link android.view.Display#STATE_DOZE}. */ void setDozeScreenState(int state); + + /** Request waking up. */ + void requestWakeUp(); } } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java index 6186df14ef3f..e55a59722385 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java @@ -16,6 +16,8 @@ package com.android.systemui.doze; +import android.os.PowerManager; +import android.os.SystemClock; import android.service.dreams.DreamService; import android.util.Log; @@ -72,4 +74,10 @@ public class DozeService extends DreamService implements DozeMachine.Service { mDozeMachine.dump(pw); } } + + @Override + public void requestWakeUp() { + PowerManager pm = getSystemService(PowerManager.class); + pm.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:NODOZE"); + } } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index db5a3921db9d..b5c7dd3bfc66 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -97,7 +97,11 @@ public class DozeTriggers implements DozeMachine.Part { } private void onSensor(int pulseReason, boolean sensorPerformedProxCheck) { - requestPulse(pulseReason, sensorPerformedProxCheck); + if (mDozeParameters.getSensorsWakeUpFully()) { + mMachine.wakeUp(); + } else { + requestPulse(pulseReason, sensorPerformedProxCheck); + } if (pulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP) { final long timeSinceNotification = diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index e8c0050ef6d1..d832810e4812 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -37,9 +37,7 @@ import android.view.ViewConfiguration; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.policy.PipSnapAlgorithm; -import com.android.systemui.Dependency; import com.android.systemui.statusbar.FlingAnimationUtils; -import com.android.systemui.tuner.TunerService; import java.io.PrintWriter; @@ -47,17 +45,18 @@ import java.io.PrintWriter; * Manages all the touch handling for PIP on the Phone, including moving, dismissing and expanding * the PIP. */ -public class PipTouchHandler implements TunerService.Tunable { +public class PipTouchHandler { private static final String TAG = "PipTouchHandler"; // These values are used for metrics and should never change private static final int METRIC_VALUE_DISMISSED_BY_TAP = 0; private static final int METRIC_VALUE_DISMISSED_BY_DRAG = 1; - private static final String TUNER_KEY_DRAG_TO_DISMISS = "pip_drag_to_dismiss"; - private static final int SHOW_DISMISS_AFFORDANCE_DELAY = 200; + // Allow dragging the PIP to a location to close it + private static final boolean ENABLE_DRAG_TO_DISMISS = false; + private final Context mContext; private final IActivityManager mActivityManager; private final IWindowManager mWindowManager; @@ -70,9 +69,6 @@ public class PipTouchHandler implements TunerService.Tunable { private final PipDismissViewController mDismissViewController; private final PipSnapAlgorithm mSnapAlgorithm; - // Allow dragging the PIP to a location to close it - private boolean mEnableDragToDismiss = false; - // The current movement bounds private Rect mMovementBounds = new Rect(); @@ -86,7 +82,7 @@ public class PipTouchHandler implements TunerService.Tunable { private Runnable mShowDismissAffordance = new Runnable() { @Override public void run() { - if (mEnableDragToDismiss) { + if (ENABLE_DRAG_TO_DISMISS) { mDismissViewController.showDismissTarget(mMotionHelper.getBounds()); } } @@ -183,23 +179,6 @@ public class PipTouchHandler implements TunerService.Tunable { mMotionHelper = new PipMotionHelper(mContext, mActivityManager, mSnapAlgorithm, mFlingAnimationUtils); registerInputConsumer(); - - // Register any tuner settings changes - Dependency.get(TunerService.class).addTunable(this, TUNER_KEY_DRAG_TO_DISMISS); - } - - @Override - public void onTuningChanged(String key, String newValue) { - if (newValue == null) { - // Reset back to default - mEnableDragToDismiss = false; - return; - } - switch (key) { - case TUNER_KEY_DRAG_TO_DISMISS: - mEnableDragToDismiss = Integer.parseInt(newValue) != 0; - break; - } } public void onActivityPinned() { @@ -439,7 +418,7 @@ public class PipTouchHandler implements TunerService.Tunable { @Override public void onDown(PipTouchState touchState) { - if (mEnableDragToDismiss) { + if (ENABLE_DRAG_TO_DISMISS) { mDismissViewController.createDismissTarget(); mHandler.postDelayed(mShowDismissAffordance, SHOW_DISMISS_AFFORDANCE_DELAY); } @@ -451,7 +430,7 @@ public class PipTouchHandler implements TunerService.Tunable { mSavedSnapFraction = -1f; } - if (touchState.startedDragging() && mEnableDragToDismiss) { + if (touchState.startedDragging() && ENABLE_DRAG_TO_DISMISS) { mHandler.removeCallbacks(mShowDismissAffordance); mDismissViewController.showDismissTarget(mMotionHelper.getBounds()); } @@ -469,7 +448,7 @@ public class PipTouchHandler implements TunerService.Tunable { mTmpBounds.offsetTo((int) left, (int) top); mMotionHelper.movePip(mTmpBounds); - if (mEnableDragToDismiss) { + if (ENABLE_DRAG_TO_DISMISS) { mDismissViewController.updateDismissTarget(mTmpBounds); } return true; @@ -480,7 +459,7 @@ public class PipTouchHandler implements TunerService.Tunable { @Override public boolean onUp(PipTouchState touchState) { try { - if (mEnableDragToDismiss) { + if (ENABLE_DRAG_TO_DISMISS) { mHandler.removeCallbacks(mShowDismissAffordance); PointF vel = mTouchState.getVelocity(); final float velocity = PointF.length(vel.x, vel.y); @@ -583,7 +562,7 @@ public class PipTouchHandler implements TunerService.Tunable { pw.println(innerPrefix + "mIsImeShowing=" + mIsImeShowing); pw.println(innerPrefix + "mImeHeight=" + mImeHeight); pw.println(innerPrefix + "mSavedSnapFraction=" + mSavedSnapFraction); - pw.println(innerPrefix + "mEnableDragToDismiss=" + mEnableDragToDismiss); + pw.println(innerPrefix + "mEnableDragToDismiss=" + ENABLE_DRAG_TO_DISMISS); mSnapAlgorithm.dump(pw, innerPrefix); mTouchState.dump(pw, innerPrefix); mMotionHelper.dump(pw, innerPrefix); diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java index a231e791e3b0..35592576043d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java +++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java @@ -242,7 +242,7 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { maxHeight = height; } } - setMeasuredDimension(getMeasuredWidth(), maxHeight); + setMeasuredDimension(getMeasuredWidth(), maxHeight + getPaddingBottom()); } private final Runnable mDistribute = new Runnable() { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java index c85f83ba3588..e0d1cba401a1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java @@ -160,7 +160,9 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha mAllViews.clear(); mTopFiveQs.clear(); - mAllViews.add((View) mQsPanel.getTileLayout()); + QSTileLayout tileLayout = mQsPanel.getTileLayout(); + mAllViews.add((View) tileLayout); + firstPageBuilder.addFloat(tileLayout, "translationY", mQsPanel.getHeight(), 0); for (QSTile<?> tile : tiles) { QSTileBaseView tileView = mQsPanel.getTileView(tile); @@ -168,7 +170,6 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha Log.e(TAG, "tileView is null " + tile.getTileSpec()); continue; } - final TextView label = ((QSTileView) tileView).getLabel(); final View tileIcon = tileView.getIcon().getIconView(); View view = mQs.getView(); if (count < mNumQuickTiles && mAllowFancy) { @@ -187,12 +188,12 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha // Counteract the parent translation on the tile. So we have a static base to // animate the label position off from. - firstPageBuilder.addFloat(tileView, "translationY", mQsPanel.getHeight(), 0); + //firstPageBuilder.addFloat(tileView, "translationY", mQsPanel.getHeight(), 0); - // Move the real tile's label from the quick tile position to its final + // Move the real tile from the quick tile position to its final // location. - translationXBuilder.addFloat(label, "translationX", -xDiff, 0); - translationYBuilder.addFloat(label, "translationY", -yDiff, 0); + translationXBuilder.addFloat(tileView, "translationX", -xDiff, 0); + translationYBuilder.addFloat(tileView, "translationY", -yDiff, 0); mTopFiveQs.add(tileView.getIcon()); mAllViews.add(tileView.getIcon()); @@ -209,22 +210,22 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha firstPageBuilder.addFloat(tileView, "translationY", mQsPanel.getHeight(), 0); translationXBuilder.addFloat(tileView, "translationX", -xDiff, 0); - translationYBuilder.addFloat(label, "translationY", -yDiff, 0); + translationYBuilder.addFloat(tileView, "translationY", -yDiff, 0); translationYBuilder.addFloat(tileIcon, "translationY", -yDiff, 0); mAllViews.add(tileIcon); } else { firstPageBuilder.addFloat(tileView, "alpha", 0, 1); + firstPageBuilder.addFloat(tileView, "translationY", -mQsPanel.getHeight(), 0); } mAllViews.add(tileView); - mAllViews.add(label); count++; } if (mAllowFancy) { // Make brightness appear static position and alpha in through second half. View brightness = mQsPanel.getBrightnessView(); if (brightness != null) { -// firstPageBuilder.addFloat(brightness, "translationY", mQsPanel.getHeight(), 0); + firstPageBuilder.addFloat(brightness, "translationY", mQsPanel.getHeight(), 0); mBrightnessAnimator = new TouchAnimator.Builder() .addFloat(brightness, "alpha", 0, 1) .addFloat(mQsPanel.getPageIndicator(), "alpha", 0, 1) @@ -240,7 +241,7 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha // Fade in the tiles/labels as we reach the final position. mFirstPageDelayedAnimator = new TouchAnimator.Builder() .setStartDelay(EXPANDED_TILE_DELAY) - .addFloat(mQsPanel.getTileLayout(), "alpha", 0, 1) + .addFloat(tileLayout, "alpha", 0, 1) .addFloat(mQsPanel.getFooter().getView(), "alpha", 0, 1).build(); mAllViews.add(mQsPanel.getFooter().getView()); float px = 0; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index 1569b0ca0249..e8d5ece2072c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -441,8 +441,15 @@ public class QSPanel extends LinearLayout implements Tunable, Callback { } r.tile.setDetailListening(show); int x = r.tileView.getLeft() + r.tileView.getWidth() / 2; - int y = r.tileView.getTop() + mTileLayout.getOffsetTop(r) + r.tileView.getHeight() / 2 - + getTop(); + int y; + if (r.tileView instanceof QSTileView) { + View labelContainer = (View) ((QSTileView) r.tileView).getLabel().getParent(); + y = r.tileView.getTop() + mTileLayout.getOffsetTop(r) + getTop() + + labelContainer.getTop() + labelContainer.getHeight() / 2; + } else { + y = r.tileView.getTop() + mTileLayout.getOffsetTop(r) + r.tileView.getHeight() / 2 + + getTop(); + } handleShowDetailImpl(r, show, x, y); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java index 0e04d0a0c825..c750fdcd9fad 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java @@ -15,38 +15,30 @@ */ package com.android.systemui.qs; -import android.animation.ValueAnimator; import android.content.Context; -import android.content.res.ColorStateList; import android.content.res.TypedArray; -import android.graphics.Color; import android.graphics.drawable.Drawable; import android.graphics.drawable.RippleDrawable; import android.os.Handler; import android.os.Looper; import android.os.Message; -import android.service.quicksettings.Tile; import android.text.TextUtils; -import android.util.Log; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.ImageView.ScaleType; import android.widget.LinearLayout; import android.widget.Switch; -import com.android.settingslib.Utils; - import com.android.systemui.R; public class QSTileBaseView extends LinearLayout { private static final String TAG = "QSTileBaseView"; private final H mHandler = new H(); + private final FrameLayout mIconFrame; protected QSIconView mIcon; protected RippleDrawable mRipple; private Drawable mTileBackground; @@ -63,15 +55,15 @@ public class QSTileBaseView extends LinearLayout { // Default to Quick Tile padding, and QSTileView will specify its own padding. int padding = context.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_padding); - FrameLayout frame = new FrameLayout(context); - frame.setForegroundGravity(Gravity.CENTER); + mIconFrame = new FrameLayout(context); + mIconFrame.setForegroundGravity(Gravity.CENTER); int size = context.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size); - addView(frame, new LayoutParams(size, size)); + addView(mIconFrame, new LayoutParams(size, size)); mIcon = icon; FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); params.setMargins(0, padding, 0, padding); - frame.addView(mIcon, params); + mIconFrame.addView(mIcon, params); mTileBackground = newTileBackground(); if (mTileBackground instanceof RippleDrawable) { @@ -105,7 +97,7 @@ public class QSTileBaseView extends LinearLayout { private void updateRippleSize(int width, int height) { // center the touch feedback on the center of the icon, and dial it down a bit final int cx = width / 2; - final int cy = height / 2; + final int cy = mIconFrame.getMeasuredHeight() / 2; final int rad = (int) (mIcon.getHeight() * .85f); mRipple.setHotspotBounds(cx - rad, cy - rad, cx + rad, cy + rad); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java index 232941dc629b..428fe9bbff7e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java @@ -20,6 +20,7 @@ import static com.android.systemui.qs.QSTile.getColorForState; import android.content.Context; import android.content.res.Configuration; +import android.graphics.drawable.RippleDrawable; import android.service.quicksettings.Tile; import android.text.SpannableStringBuilder; import android.text.style.ForegroundColorSpan; @@ -28,6 +29,7 @@ import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; +import android.view.ViewGroup.LayoutParams; import android.widget.ImageView; import android.widget.TextView; @@ -43,8 +45,7 @@ public class QSTileView extends QSTileBaseView { protected TextView mLabel; private ImageView mPadLock; private int mState; - private OnClickListener mClick; - private OnClickListener mSecondaryClick; + private ViewGroup mLabelContainer; public QSTileView(Context context, QSIconView icon) { this(context, icon, false); @@ -76,13 +77,15 @@ public class QSTileView extends QSTileBaseView { } protected void createLabel() { - ViewGroup view = (ViewGroup) LayoutInflater.from(getContext()) - .inflate(R.layout.qs_tile_label, null); - view.setClipChildren(false); - view.setClipToPadding(false); - mLabel = (TextView) view.findViewById(R.id.tile_label); - mPadLock = (ImageView) view.findViewById(R.id.restricted_padlock); - addView(view); + mLabelContainer = (ViewGroup) LayoutInflater.from(getContext()) + .inflate(R.layout.qs_tile_label, this, false); + mLabelContainer.setClipChildren(false); + mLabelContainer.setClipToPadding(false); + mLabel = (TextView) mLabelContainer.findViewById(R.id.tile_label); + mPadLock = (ImageView) mLabelContainer.findViewById(R.id.restricted_padlock); + + mLabelContainer.setBackground(newTileBackground()); + addView(mLabelContainer); } @Override @@ -104,17 +107,10 @@ public class QSTileView extends QSTileBaseView { } @Override - public void init(OnClickListener click, OnClickListener secondaryClick, OnLongClickListener longClick) { - mClick = click; - mSecondaryClick = secondaryClick; + public void init(OnClickListener click, OnClickListener secondaryClick, + OnLongClickListener longClick) { super.init(click, secondaryClick, longClick); - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - if (event.getActionMasked() == MotionEvent.ACTION_UP) { - setOnClickListener(event.getY() < (getMeasuredHeight() / 2) ? mClick : mSecondaryClick); - } - return super.onTouchEvent(event); + mLabelContainer.setClickable(true); + mLabelContainer.setOnClickListener(secondaryClick); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java index 8227f8f63ceb..f7bfc1e6d4fc 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java @@ -104,11 +104,6 @@ public class BatteryTile extends QSTile<QSTile.State> implements BatteryControll } @Override - protected void handleSecondaryClick() { - showDetail(true); - } - - @Override public CharSequence getTileLabel() { return mContext.getString(R.string.battery); } @@ -118,7 +113,6 @@ public class BatteryTile extends QSTile<QSTile.State> implements BatteryControll int level = (arg != null) ? (Integer) arg : mLevel; String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0); - state.dualTarget = true; state.state = mCharging ? Tile.STATE_UNAVAILABLE : mPowerSave ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE; state.icon = ResourceIcon.get(R.drawable.ic_qs_battery_saver); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java index b48b829d14f7..3c28f7602c18 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java @@ -123,7 +123,6 @@ public class CastTile extends QSTile<QSTile.BooleanState> { @Override protected void handleUpdateState(BooleanState state, Object arg) { - state.dualTarget = true; state.label = mContext.getString(R.string.quick_settings_cast_title); state.contentDescription = state.label; state.value = false; diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index a6fe0ea2ea73..c9debb2068b7 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -31,6 +31,7 @@ import android.os.Handler; import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; +import android.provider.Settings.Secure; import android.util.Log; import android.view.KeyEvent; import android.view.View; @@ -44,7 +45,6 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.DejankUtils; import com.android.systemui.Interpolators; import com.android.keyguard.LatencyTracker; -import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent; @@ -181,8 +181,10 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD // is still valid. Otherwise, we need to reset the lastStackactiveTime to the // currentTime and remove the old tasks in between which would not be previously // visible, but currently would be in the new currentTime - long oldLastStackActiveTime = Prefs.getLong(RecentsActivity.this, - Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, -1); + int currentUser = SystemServicesProxy.getInstance(RecentsActivity.this) + .getCurrentUser(); + long oldLastStackActiveTime = Settings.Secure.getLongForUser(getContentResolver(), + Secure.OVERVIEW_LAST_STACK_ACTIVE_TIME, -1, currentUser); if (oldLastStackActiveTime != -1) { long currentTime = System.currentTimeMillis(); if (currentTime < oldLastStackActiveTime) { @@ -200,8 +202,8 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD Recents.getSystemServices().removeTask(task.persistentId); } } - Prefs.putLong(RecentsActivity.this, - Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, currentTime); + Settings.Secure.putLongForUser(RecentsActivity.this.getContentResolver(), + Secure.OVERVIEW_LAST_STACK_ACTIVE_TIME, currentTime, currentUser); } } } @@ -834,8 +836,9 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD Recents.getTaskLoader().dump(prefix, writer); String id = Integer.toHexString(System.identityHashCode(this)); - long lastStackActiveTime = Prefs.getLong(this, - Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, -1); + long lastStackActiveTime = Settings.Secure.getLongForUser(getContentResolver(), + Secure.OVERVIEW_LAST_STACK_ACTIVE_TIME, -1, + SystemServicesProxy.getInstance(this).getCurrentUser()); writer.print(prefix); writer.print(TAG); writer.print(" visible="); writer.print(mIsVisible ? "Y" : "N"); diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java index 11b598478bfb..12c10dff0ab3 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java @@ -26,6 +26,8 @@ import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.os.UserHandle; import android.os.UserManager; +import android.provider.Settings; +import android.provider.Settings.Secure; import android.util.ArraySet; import android.util.SparseArray; import android.util.SparseBooleanArray; @@ -130,6 +132,7 @@ public class RecentsTaskLoadPlan { preloadRawTasks(includeFrontMostExcludedTask); } + SystemServicesProxy ssp = SystemServicesProxy.getInstance(mContext); SparseArray<Task.TaskKey> affiliatedTasks = new SparseArray<>(); SparseIntArray affiliatedTaskCounts = new SparseIntArray(); SparseBooleanArray lockedUsers = new SparseBooleanArray(); @@ -137,8 +140,10 @@ public class RecentsTaskLoadPlan { R.string.accessibility_recents_item_will_be_dismissed); String appInfoDescFormat = mContext.getString( R.string.accessibility_recents_item_open_app_info); - long lastStackActiveTime = Prefs.getLong(mContext, - Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, 0); + int currentUserId = ssp.getCurrentUser(); + long legacyLastStackActiveTime = migrateLegacyLastStackActiveTime(currentUserId); + long lastStackActiveTime = Settings.Secure.getLongForUser(mContext.getContentResolver(), + Secure.OVERVIEW_LAST_STACK_ACTIVE_TIME, legacyLastStackActiveTime, currentUserId); if (RecentsDebugFlags.Static.EnableMockTasks) { lastStackActiveTime = 0; } @@ -205,8 +210,8 @@ public class RecentsTaskLoadPlan { affiliatedTasks.put(taskKey.id, taskKey); } if (newLastStackActiveTime != -1) { - Prefs.putLong(mContext, Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, - newLastStackActiveTime); + Settings.Secure.putLongForUser(mContext.getContentResolver(), + Secure.OVERVIEW_LAST_STACK_ACTIVE_TIME, newLastStackActiveTime, currentUserId); } // Initialize the stacks @@ -285,4 +290,36 @@ public class RecentsTaskLoadPlan { private boolean isHistoricalTask(ActivityManager.RecentTaskInfo t) { return t.lastActiveTime < (System.currentTimeMillis() - SESSION_BEGIN_TIME); } + + + /** + * Migrate the last active time from the prefs to the secure settings. + * + * The first time this runs, it will: + * 1) fetch the last stack active time from the prefs + * 2) set the prefs to the last stack active time for all users + * 3) clear the pref + * 4) return the last stack active time + * + * Subsequent calls to this will return zero. + */ + private long migrateLegacyLastStackActiveTime(int currentUserId) { + long legacyLastStackActiveTime = Prefs.getLong(mContext, + Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, -1); + if (legacyLastStackActiveTime != -1) { + Prefs.remove(mContext, Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME); + UserManager userMgr = (UserManager) mContext.getSystemService(Context.USER_SERVICE); + List<UserInfo> users = userMgr.getUsers(); + for (int i = 0; i < users.size(); i++) { + int userId = users.get(i).id; + if (userId != currentUserId) { + Settings.Secure.putLongForUser(mContext.getContentResolver(), + Secure.OVERVIEW_LAST_STACK_ACTIVE_TIME, legacyLastStackActiveTime, + userId); + } + } + return legacyLastStackActiveTime; + } + return 0; + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java index 3648a060e619..cb4306f0d137 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java @@ -462,6 +462,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { updateBackgroundForGroupState(); updateClickAndFocus(); if (mNotificationParent != null) { + setOverrideTintColor(NO_COLOR, 0.0f); mNotificationParent.updateBackgroundForGroupState(); } updateIconVisibilities(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index d599ec1a2062..bc992d821998 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java @@ -87,6 +87,7 @@ public class KeyguardIndicationController { private KeyguardUpdateMonitorCallback mUpdateMonitor; private final DevicePolicyManager mDevicePolicyManager; + private boolean mDozing; public KeyguardIndicationController(Context context, ViewGroup indicationArea, LockIcon lockIcon) { @@ -139,7 +140,7 @@ public class KeyguardIndicationController { return; } - if (mDevicePolicyManager.isDeviceManaged()) { + if (!mDozing && mDevicePolicyManager.isDeviceManaged()) { final CharSequence organizationName = mDevicePolicyManager.getDeviceOwnerOrganizationName(); if (organizationName != null) { @@ -224,6 +225,18 @@ public class KeyguardIndicationController { if (mVisible) { // Walk down a precedence-ordered list of what should indication // should be shown based on user or device state + if (mDozing) { + // If we're dozing, never show a persistent indication. + if (!TextUtils.isEmpty(mTransientIndication)) { + mTextView.switchIndication(mTransientIndication); + mTextView.setTextColor(mTransientTextColor); + + } else { + mTextView.switchIndication(null); + } + return; + } + if (!mUserManager.isUserUnlocked(ActivityManager.getCurrentUser())) { mTextView.switchIndication(com.android.internal.R.string.lockscreen_storage_locked); mTextView.setTextColor(Color.WHITE); @@ -319,6 +332,12 @@ public class KeyguardIndicationController { } }; + public void setDozing(boolean dozing) { + mDozing = dozing; + updateIndication(); + updateDisclosure(); + } + protected class BaseKeyguardCallback extends KeyguardUpdateMonitorCallback { private int mLastSuccessiveErrorMessage = -1; @@ -349,7 +368,8 @@ public class KeyguardIndicationController { int errorColor = mContext.getResources().getColor(R.color.system_warning_color, null); if (mStatusBarKeyguardViewManager.isBouncerShowing()) { mStatusBarKeyguardViewManager.showBouncerMessage(helpString, errorColor); - } else if (updateMonitor.isDeviceInteractive()) { + } else if (updateMonitor.isDeviceInteractive() + || mDozing && updateMonitor.isScreenOn()) { mLockIcon.setTransientFpError(true); showTransientIndication(helpString, errorColor); mHandler.removeMessages(MSG_CLEAR_FP_MSG); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java index 0e074c7b8710..883a66b59531 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java @@ -31,6 +31,7 @@ import java.io.PrintWriter; public class DozeParameters { private static final int MAX_DURATION = 60 * 1000; + public static final String DOZE_SENSORS_WAKE_UP_FULLY = "doze_sensors_wake_up_fully"; private final Context mContext; @@ -56,6 +57,10 @@ public class DozeParameters { pw.print(" getPickupVibrationThreshold(): "); pw.println(getPickupVibrationThreshold()); pw.print(" getPickupSubtypePerformsProxCheck(): ");pw.println( dumpPickupSubtypePerformsProxCheck()); + if (Build.IS_DEBUGGABLE) { + pw.print(" getAlwaysOn(): "); pw.println(getAlwaysOn()); + pw.print(" getSensorsWakeUpFully(): "); pw.println(getSensorsWakeUpFully()); + } } private String dumpPickupSubtypePerformsProxCheck() { @@ -118,6 +123,12 @@ public class DozeParameters { Settings.Secure.DOZE_ALWAYS_ON, 0, UserHandle.USER_CURRENT) != 0; } + public boolean getSensorsWakeUpFully() { + return Build.IS_DEBUGGABLE + && Settings.Secure.getIntForUser(mContext.getContentResolver(), + DOZE_SENSORS_WAKE_UP_FULLY, 0, UserHandle.USER_CURRENT) != 0; + } + private boolean getBoolean(String propName, int resId) { return SystemProperties.getBoolean(propName, mContext.getResources().getBoolean(resId)); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index 2b335f44b485..8f63d45e04cd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -167,6 +167,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private IntentButton mLeftPlugin; private String mLeftButtonStr; private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger(); + private boolean mDozing; public KeyguardBottomAreaView(Context context) { this(context, null); @@ -361,7 +362,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL // Things are not set up yet; reply hazy, ask again later return; } - mRightAffordanceView.setVisibility(mRightButton.getIcon().isVisible + mRightAffordanceView.setVisibility(!mDozing && mRightButton.getIcon().isVisible ? View.VISIBLE : View.GONE); } @@ -375,7 +376,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private void updateLeftAffordanceIcon() { IconState state = mLeftButton.getIcon(); - mLeftAffordanceView.setVisibility(state.isVisible ? View.VISIBLE : View.GONE); + mLeftAffordanceView.setVisibility(!mDozing && state.isVisible ? View.VISIBLE : View.GONE); mLeftAffordanceView.setImageDrawable(state.drawable, state.tint); mLeftAffordanceView.setContentDescription(state.contentDescription); } @@ -846,6 +847,22 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL } }; + public void setDozing(boolean dozing, boolean animate) { + mDozing = dozing; + + updateCameraVisibility(); + updateLeftAffordanceIcon(); + + if (dozing) { + mLockIcon.setVisibility(INVISIBLE); + } else { + mLockIcon.setVisibility(VISIBLE); + if (animate) { + startFinishDozeAnimation(); + } + } + } + private class DefaultLeftButton implements IntentButton { private IconState mIconState = new IconState(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 5da3a101b4bb..6da9e9022c88 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -1151,9 +1151,7 @@ public class NotificationPanelView extends PanelView implements .start(); } else if (statusBarState == StatusBarState.KEYGUARD || statusBarState == StatusBarState.SHADE_LOCKED) { - if (!mDozing) { - mKeyguardBottomArea.setVisibility(View.VISIBLE); - } + mKeyguardBottomArea.setVisibility(View.VISIBLE); mKeyguardBottomArea.setAlpha(1f); } else { mKeyguardBottomArea.setVisibility(View.GONE); @@ -2103,13 +2101,12 @@ public class NotificationPanelView extends PanelView implements private void updateDozingVisibilities(boolean animate) { if (mDozing) { mKeyguardStatusBar.setVisibility(View.INVISIBLE); - mKeyguardBottomArea.setVisibility(View.INVISIBLE); + mKeyguardBottomArea.setDozing(mDozing, animate); } else { - mKeyguardBottomArea.setVisibility(View.VISIBLE); mKeyguardStatusBar.setVisibility(View.VISIBLE); + mKeyguardBottomArea.setDozing(mDozing, animate); if (animate) { animateKeyguardStatusBarIn(DOZE_ANIMATION_DURATION); - mKeyguardBottomArea.startFinishDozeAnimation(); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java index 457ed6cc4237..ade1b0b6844e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java @@ -26,7 +26,6 @@ import android.graphics.Color; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.graphics.drawable.RippleDrawable; -import android.icu.text.NumberFormat; import android.os.UserManager; import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; @@ -55,7 +54,6 @@ import com.android.systemui.qs.QuickQSPanel; import com.android.systemui.qs.TouchAnimator; import com.android.systemui.qs.TouchAnimator.Builder; import com.android.systemui.statusbar.SignalClusterView; -import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener; import com.android.systemui.statusbar.policy.NetworkController.IconState; @@ -68,7 +66,7 @@ import com.android.systemui.tuner.TunerService; public class QuickStatusBarHeader extends BaseStatusBarHeader implements NextAlarmChangeCallback, OnClickListener, OnUserInfoChangedListener, EmergencyListener, - BatteryStateChangeCallback, SignalCallback { + SignalCallback { private static final float EXPAND_INDICATOR_THRESHOLD = .93f; private ActivityStarter mActivityStarter; @@ -110,7 +108,6 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements private boolean mShowFullAlarm; private float mDateTimeTranslation; - private TextView mBatteryLevel; private SparseBooleanArray mRoamingsBySubId = new SparseBooleanArray(); private boolean mIsRoaming; @@ -161,8 +158,6 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements mAlarmStatus = (TextView) findViewById(R.id.alarm_status); mAlarmStatus.setOnClickListener(this); - mBatteryLevel = (TextView) findViewById(R.id.battery_level); - mMultiUserSwitch = (MultiUserSwitch) findViewById(R.id.multi_user_switch); mMultiUserAvatar = (ImageView) mMultiUserSwitch.findViewById(R.id.multi_user_avatar); mAlwaysShowMultiUserSwitch = res.getBoolean(R.bool.config_alwaysShowMultiUserSwitcher); @@ -179,7 +174,9 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements int colorForeground = Utils.getColorAttr(getContext(), android.R.attr.colorForeground); float intensity = colorForeground == Color.WHITE ? 0 : 1; cluster.onDarkChanged(new Rect(0, 0, 0, 0), intensity, colorForeground); + BatteryMeterView battery = (BatteryMeterView) findViewById(R.id.battery); + battery.forceShowPercent(); int colorSecondary = Utils.getColorAttr(getContext(), android.R.attr.textColorSecondary); battery.setRawColors(colorForeground, colorSecondary); @@ -443,17 +440,6 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements } } - @Override - public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { - String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0); - mBatteryLevel.setText(percentage); - } - - @Override - public void onPowerSaveChanged(boolean isPowerSave) { - // Don't care. - } - public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType, int qsType, boolean activityIn, boolean activityOut, String typeContentDescription, String description, boolean isWide, int subId, boolean roaming) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index cfbcf8c3d95b..3d6e4b3cd3b5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -4322,6 +4322,7 @@ public class StatusBar extends SystemUI implements DemoMode, mNotificationPanel.setDozing(mDozing, animate); mStackScroller.setDark(mDozing, animate, mWakeUpTouchLocation); mScrimController.setDozing(mDozing); + mKeyguardIndicationController.setDozing(mDozing); // Immediately abort the dozing from the doze scrim controller in case of wake-and-unlock // for pulsing so the Keyguard fade-out animation scrim can take over. diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java index c3948258f11c..32afee9744d5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java @@ -289,4 +289,12 @@ public class DozeMachineTest { assertEquals(DOZE_PULSING, mMachine.getState()); } + + @Test + @UiThreadTest + public void testWakeUp_wakesUp() { + mMachine.wakeUp(); + + assertTrue(mServiceFake.requestedWakeup); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeServiceFake.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeServiceFake.java index d12fc2cf33a0..c1e7fe46de8e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeServiceFake.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeServiceFake.java @@ -22,6 +22,7 @@ public class DozeServiceFake implements DozeMachine.Service { public boolean finished; public int screenState; + public boolean requestedWakeup; public DozeServiceFake() { reset(); @@ -41,4 +42,9 @@ public class DozeServiceFake implements DozeMachine.Service { finished = false; screenState = Display.STATE_UNKNOWN; } + + @Override + public void requestWakeUp() { + requestedWakeup = true; + } } diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index 245bf9ed31be..8d2f0c3145bf 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -3410,6 +3410,25 @@ message MetricsEvent { // OS: O NOTIFICATION_SNOOZED_CRITERIA = 832; + // FIELD - The context (source) from which an action is performed + FIELD_CONTEXT = 833; + + // ACTION: Settings advanced button is expanded + ACTION_SETTINGS_ADVANCED_BUTTON_EXPAND = 834; + + // ACTION: Logs the number of times the saved network evaluator was used to + // recommend a wifi network + WIFI_NETWORK_RECOMMENDATION_SAVED_NETWORK_EVALUATOR = 835; + + // ACTION: Logs the number of times the recommended network evaluator was + // used to recommend a wifi network + WIFI_NETWORK_RECOMMENDATION_RECOMMENDED_NETWORK_EVALUATOR = 836; + + // ACTION: Logs the number of times a recommended network was resulted in a + // successful connection + // VALUE: true if the connection was successful, false if the connection failed + WIFI_NETWORK_RECOMMENDATION_CONNECTION_SUCCESS = 837; + // ---- End O Constants, all O constants go above this line ---- // Add new aosp constants above this line. diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 719a64e32241..fe0b8401a6cd 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -4166,7 +4166,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } ensureRequestableCapabilities(networkCapabilities); - if (timeoutMs < 0 || timeoutMs > ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS) { + if (timeoutMs < 0) { throw new IllegalArgumentException("Bad timeout specified"); } diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java index dc987fac97e5..e6f6e5764d95 100644 --- a/services/core/java/com/android/server/InputMethodManagerService.java +++ b/services/core/java/com/android/server/InputMethodManagerService.java @@ -901,7 +901,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mPackagesToMonitorComponentChange.add(packageName); } - private boolean isChangingPackagesOfCurrentUser() { + @GuardedBy("mMethodMap") + private boolean isChangingPackagesOfCurrentUserLocked() { final int userId = getChangingUserId(); final boolean retval = userId == mSettings.getCurrentUserId(); if (DEBUG) { @@ -914,10 +915,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @Override public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) { - if (!isChangingPackagesOfCurrentUser()) { - return false; - } synchronized (mMethodMap) { + if (!isChangingPackagesOfCurrentUserLocked()) { + return false; + } String curInputMethodId = mSettings.getSelectedInputMethod(); final int N = mMethodList.size(); if (curInputMethodId != null) { @@ -951,10 +952,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub @Override public void onSomePackagesChanged() { - if (!isChangingPackagesOfCurrentUser()) { - return; - } synchronized (mMethodMap) { + if (!isChangingPackagesOfCurrentUserLocked()) { + return; + } InputMethodInfo curIm = null; String curInputMethodId = mSettings.getSelectedInputMethod(); final int N = mMethodList.size(); diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index 42eb958bba0b..ef7780c79126 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -19,6 +19,7 @@ package com.android.server; import android.app.ActivityManager; import android.annotation.NonNull; import android.content.pm.PackageManagerInternal; +import android.util.ArraySet; import com.android.internal.content.PackageMonitor; import com.android.internal.location.ProviderProperties; import com.android.internal.location.ProviderRequest; @@ -135,8 +136,6 @@ public class LocationManagerService extends ILocationManager.Stub { private static final String FUSED_LOCATION_SERVICE_ACTION = "com.android.location.service.FusedLocationProvider"; - private static final String GMSCORE_PACKAGE = "com.android.google.gms"; - private static final int MSG_LOCATION_CHANGED = 1; private static final long NANOS_PER_MILLI = 1000000L; @@ -224,7 +223,7 @@ public class LocationManagerService extends ILocationManager.Stub { private final ArrayList<LocationProviderProxy> mProxyProviders = new ArrayList<>(); - private String[] mBackgroundThrottlePackageWhitelist = new String[]{}; + private final ArraySet<String> mBackgroundThrottlePackageWhitelist = new ArraySet<>(); // current active user on the device - other users are denied location data private int mCurrentUserId = UserHandle.USER_SYSTEM; @@ -345,6 +344,8 @@ public class LocationManagerService extends ILocationManager.Stub { mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); updateUserProfiles(mCurrentUserId); + updateThrottlingWhitelistLocked(); + // prepare providers loadProvidersLocked(); updateProvidersLocked(); @@ -380,14 +381,7 @@ public class LocationManagerService extends ILocationManager.Stub { @Override public void onChange(boolean selfChange) { synchronized (mLock) { - String setting = Settings.Global.getString( - mContext.getContentResolver(), - Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST); - if (setting == null) { - setting = ""; - } - - mBackgroundThrottlePackageWhitelist = setting.split(","); + updateThrottlingWhitelistLocked(); updateProvidersLocked(); } } @@ -1747,12 +1741,27 @@ public class LocationManagerService extends ILocationManager.Stub { p.setRequest(providerRequest, worksource); } + private void updateThrottlingWhitelistLocked() { + String setting = Settings.Global.getString( + mContext.getContentResolver(), + Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST); + if (setting == null) { + setting = ""; + } + + mBackgroundThrottlePackageWhitelist.clear(); + mBackgroundThrottlePackageWhitelist.addAll( + SystemConfig.getInstance().getAllowUnthrottledLocation()); + mBackgroundThrottlePackageWhitelist.addAll( + Arrays.asList(setting.split(","))); + } + private boolean isThrottlingExemptLocked(Receiver receiver) { if (receiver.mUid == Process.SYSTEM_UID) { return true; } - if (receiver.mPackageName.equals(GMSCORE_PACKAGE)) { + if (mBackgroundThrottlePackageWhitelist.contains(receiver.mPackageName)) { return true; } @@ -1762,12 +1771,6 @@ public class LocationManagerService extends ILocationManager.Stub { } } - for (String whitelistedPackage : mBackgroundThrottlePackageWhitelist) { - if (receiver.mPackageName.equals(whitelistedPackage)) { - return true; - } - } - return false; } @@ -2999,6 +3002,13 @@ public class LocationManagerService extends ILocationManager.Stub { } } + if (!mBackgroundThrottlePackageWhitelist.isEmpty()) { + pw.println(" Throttling Whitelisted Packages:"); + for (String packageName : mBackgroundThrottlePackageWhitelist) { + pw.println(" " + packageName); + } + } + pw.append(" fudger: "); mLocationFudger.dump(fd, pw, args); diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java index 3e8985295c66..b33538cbcb07 100644 --- a/services/core/java/com/android/server/NetworkScoreService.java +++ b/services/core/java/com/android/server/NetworkScoreService.java @@ -603,7 +603,10 @@ public class NetworkScoreService extends INetworkScoreService.Stub { mScanResultKeys = new ArraySet<>(size); for (int i = 0; i < size; i++) { ScanResult scanResult = scanResults.get(i); - mScanResultKeys.add(NetworkKey.createFromScanResult(scanResult)); + NetworkKey key = NetworkKey.createFromScanResult(scanResult); + if (key != null) { + mScanResultKeys.add(key); + } } } diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index fbc444026539..5c8024ac3170 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -4087,9 +4087,10 @@ public class AccountManagerService } @Override - public void addSharedAccountsFromParentUser(int parentUserId, int userId) { + public void addSharedAccountsFromParentUser(int parentUserId, int userId, + String opPackageName) { checkManageOrCreateUsersPermission("addSharedAccountsFromParentUser"); - Account[] accounts = getAccountsAsUser(null, parentUserId, mContext.getOpPackageName()); + Account[] accounts = getAccountsAsUser(null, parentUserId, opPackageName); for (Account account : accounts) { addSharedAccountAsUser(account, userId); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index a73eb18b3c61..c2c24b37a81a 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -556,7 +556,7 @@ public class ActivityManagerService extends IActivityManager.Stub // Intent sent when remote bugreport collection has been completed private static final String INTENT_REMOTE_BUGREPORT_FINISHED = - "android.intent.action.REMOTE_BUGREPORT_FINISHED"; + "com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED"; // Used to indicate that an app transition should be animated. static final boolean ANIMATE = true; diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 7c2460421e35..f75ce250c8e2 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -2507,7 +2507,7 @@ final class ActivityStack extends ConfigurationContainer implements StackWindowL if (!next.hasBeenLaunched) { next.hasBeenLaunched = true; } else if (SHOW_APP_STARTING_PREVIEW && lastStack != null && - mStackSupervisor.isFrontStack(lastStack)) { + mStackSupervisor.isFrontStackOnDisplay(lastStack)) { next.showStartingWindow(null /* prev */, false /* newTask */, false /* taskSwitch */); } @@ -4354,7 +4354,7 @@ final class ActivityStack extends ConfigurationContainer implements StackWindowL // If we have a watcher, preflight the move before committing to it. First check // for *other* available tasks, but if none are available, then try again allowing the // current task to be selected. - if (mStackSupervisor.isFrontStack(this) && mService.mController != null) { + if (mStackSupervisor.isFrontStackOnDisplay(this) && mService.mController != null) { ActivityRecord next = topRunningActivityLocked(null, taskId); if (next == null) { next = topRunningActivityLocked(null, 0); diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 95734a4ed782..4a29872bdb72 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -624,11 +624,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return stack == mFocusedStack; } - /** The top most stack. */ - boolean isFrontStack(ActivityStack stack) { - return isFrontOfStackList(stack, mHomeStack.mStacks); - } - /** The top most stack on its display. */ boolean isFrontStackOnDisplay(ActivityStack stack) { return isFrontOfStackList(stack, stack.mActivityContainer.mActivityDisplay.mStacks); @@ -1103,13 +1098,21 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } // Look in other non-focused and non-home stacks. - final ArrayList<ActivityStack> stacks = mHomeStack.mStacks; - for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { - final ActivityStack stack = stacks.get(stackNdx); - if (stack != focusedStack && isFrontStack(stack) && stack.isFocusable()) { - r = stack.topRunningActivityLocked(); - if (r != null) { - return r; + mWindowManager.getDisplaysInFocusOrder(mTmpOrderedDisplayIds); + + for (int i = mTmpOrderedDisplayIds.size() - 1; i >= 0; --i) { + final int displayId = mTmpOrderedDisplayIds.get(i); + final List<ActivityStack> stacks = mActivityDisplays.get(displayId).mStacks; + if (stacks == null) { + continue; + } + for (int j = stacks.size() - 1; j >= 0; --j) { + final ActivityStack stack = stacks.get(j); + if (stack != focusedStack && isFrontStackOnDisplay(stack) && stack.isFocusable()) { + r = stack.topRunningActivityLocked(); + if (r != null) { + return r; + } } } } @@ -2676,7 +2679,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // 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. - final boolean wasFront = isFrontStack(prevStack) + final boolean wasFront = isFrontStackOnDisplay(prevStack) && (prevStack.topRunningActivityLocked() == r); if (stackId == DOCKED_STACK_ID && !task.isResizeable()) { diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java index 7cb223dec5f3..13370461521b 100644 --- a/services/core/java/com/android/server/job/JobServiceContext.java +++ b/services/core/java/com/android/server/job/JobServiceContext.java @@ -448,7 +448,10 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne mVerb = VERB_STARTING; scheduleOpTimeOut(); service.startJob(mParams); - } catch (RemoteException e) { + } catch (Exception e) { + // We catch 'Exception' because client-app malice or bugs might induce a wide + // range of possible exception-throw outcomes from startJob() and its handling + // of the client's ParcelableBundle extras. Slog.e(TAG, "Error sending onStart message to '" + mRunningJob.getServiceComponent().getShortClassName() + "' ", e); } diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index 17b005d8c890..8bc72dee531c 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -481,12 +481,6 @@ public class GnssLocationProvider implements LocationProviderInterface { public void onLost(Network network) { releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN); } - - @Override - public void onUnavailable() { - // timeout, it was not possible to establish the required connection - releaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED); - } }; private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @@ -877,8 +871,7 @@ public class GnssLocationProvider implements LocationProviderInterface { NetworkRequest request = requestBuilder.build(); mConnMgr.requestNetwork( request, - mSuplConnectivityCallback, - ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS); + mSuplConnectivityCallback); } private void handleReleaseSuplConnection(int agpsDataConnStatus) { diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java index 98177feef85b..407262b08392 100644 --- a/services/core/java/com/android/server/media/MediaSessionService.java +++ b/services/core/java/com/android/server/media/MediaSessionService.java @@ -93,7 +93,6 @@ public class MediaSessionService extends SystemService implements Monitor { private final SessionManagerImpl mSessionManagerImpl; private final MediaSessionStack mPriorityStack; - private final ArrayList<MediaSessionRecord> mAllSessions = new ArrayList<MediaSessionRecord>(); private final SparseArray<UserRecord> mUserRecords = new SparseArray<UserRecord>(); private final ArrayList<SessionsListenerRecord> mSessionsListeners = new ArrayList<SessionsListenerRecord>(); @@ -145,7 +144,8 @@ public class MediaSessionService extends SystemService implements Monitor { public void updateSession(MediaSessionRecord record) { synchronized (mLock) { - if (!mAllSessions.contains(record)) { + UserRecord user = mUserRecords.get(record.getUserId()); + if (user == null || !user.mSessions.contains(record)) { Log.d(TAG, "Unknown session updated. Ignoring."); return; } @@ -171,7 +171,8 @@ public class MediaSessionService extends SystemService implements Monitor { public void onSessionPlaystateChange(MediaSessionRecord record, int oldState, int newState) { boolean updateSessions = false; synchronized (mLock) { - if (!mAllSessions.contains(record)) { + UserRecord user = mUserRecords.get(record.getUserId()); + if (user == null || !user.mSessions.contains(record)) { Log.d(TAG, "Unknown session changed playback state. Ignoring."); return; } @@ -184,7 +185,8 @@ public class MediaSessionService extends SystemService implements Monitor { public void onSessionPlaybackTypeChanged(MediaSessionRecord record) { synchronized (mLock) { - if (!mAllSessions.contains(record)) { + UserRecord user = mUserRecords.get(record.getUserId()); + if (user == null || !user.mSessions.contains(record)) { Log.d(TAG, "Unknown session changed playback type. Ignoring."); return; } @@ -318,7 +320,6 @@ public class MediaSessionService extends SystemService implements Monitor { } mPriorityStack.removeSession(session); - mAllSessions.remove(session); try { session.getCallback().asBinder().unlinkToDeath(session, 0); @@ -455,7 +456,6 @@ public class MediaSessionService extends SystemService implements Monitor { throw new RuntimeException("Media Session owner died prematurely.", e); } - mAllSessions.add(session); mPriorityStack.addSession(session, mCurrentUserIdList.contains(userId)); user.addSessionLocked(session); @@ -1087,16 +1087,10 @@ public class MediaSessionService extends SystemService implements Monitor { synchronized (mLock) { pw.println(mSessionsListeners.size() + " sessions listeners."); - int count = mAllSessions.size(); - pw.println(count + " Sessions:"); - for (int i = 0; i < count; i++) { - mAllSessions.get(i).dump(pw, ""); - pw.println(); - } mPriorityStack.dump(pw, ""); pw.println("User Records:"); - count = mUserRecords.size(); + int count = mUserRecords.size(); for (int i = 0; i < count; i++) { UserRecord user = mUserRecords.get(mUserRecords.keyAt(i)); user.dumpLocked(pw, ""); diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java index 9da94b3007ee..06b6f66203aa 100644 --- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java @@ -20,6 +20,7 @@ import android.Manifest; import android.annotation.NonNull; import android.app.DownloadManager; import android.app.admin.DevicePolicyManager; +import android.companion.CompanionDeviceManager; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; @@ -673,6 +674,16 @@ final class DefaultPermissionGrantPolicy { && doesPackageSupportRuntimePermissions(storageManagerPckg)) { grantRuntimePermissionsLPw(storageManagerPckg, STORAGE_PERMISSIONS, true, userId); } + + // Companion devices + PackageParser.Package companionDeviceDiscoveryPackage = getSystemPackageLPr( + CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME); + if (companionDeviceDiscoveryPackage != null + && doesPackageSupportRuntimePermissions(companionDeviceDiscoveryPackage)) { + grantRuntimePermissionsLPw(companionDeviceDiscoveryPackage, + LOCATION_PERMISSIONS, true, userId); + } + mService.mSettings.onDefaultRuntimePermissionsGrantedLPr(userId); } } diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index db712aeba0cd..b589057ada3e 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -66,6 +66,9 @@ public class PackageDexOptimizer { public static final int DEX_OPT_PERFORMED = 1; public static final int DEX_OPT_FAILED = -1; + /** Special library name that skips shared libraries check during compilation. */ + public static final String SKIP_SHARED_LIBRARY_CHECK = "&"; + private final Installer mInstaller; private final Object mInstallLock; @@ -274,7 +277,7 @@ public class PackageDexOptimizer { // TODO(calin): maybe add a separate call. mInstaller.dexopt(path, info.uid, info.packageName, isa, /*dexoptNeeded*/ 0, /*oatDir*/ null, dexoptFlags, - compilerFilter, info.volumeUuid, /*sharedLibrariesPath*/ null); + compilerFilter, info.volumeUuid, SKIP_SHARED_LIBRARY_CHECK); } return DEX_OPT_PERFORMED; diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 0d63f72ea37f..f43e468f39ac 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -545,9 +545,6 @@ public class PackageManagerService extends IPackageManager.Stub { public static final int REASON_LAST = REASON_CORE_APP; - /** Special library name that skips shared libraries check during compilation. */ - private static final String SKIP_SHARED_LIBRARY_CHECK = "&"; - /** All dangerous permission names in the same order as the events in MetricsEvent */ private static final List<String> ALL_DANGEROUS_PERMISSIONS = Arrays.asList( Manifest.permission.READ_CALENDAR, @@ -2401,7 +2398,7 @@ public class PackageManagerService extends IPackageManager.Stub { DEXOPT_PUBLIC, getCompilerFilterForReason(REASON_SHARED_APK), StorageManager.UUID_PRIVATE_INTERNAL, - SKIP_SHARED_LIBRARY_CHECK); + PackageDexOptimizer.SKIP_SHARED_LIBRARY_CHECK); } } catch (FileNotFoundException e) { Slog.w(TAG, "Library not found: " + libPath); diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java index 3085c9cc9d29..570259ba5615 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackage.java +++ b/services/core/java/com/android/server/pm/ShortcutPackage.java @@ -1581,6 +1581,11 @@ class ShortcutPackage extends ShortcutPackageItem { Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() + " still has an icon"); } + if (si.hasMaskableBitmap() && !si.hasIconFile()) { + failed = true; + Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() + + " has maskable bitmap but was not saved to a file."); + } if (si.hasIconFile() && si.hasIconResource()) { failed = true; Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index d8857b77d961..057e781e76dd 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -1216,7 +1216,8 @@ public class ShortcutService extends IShortcutService.Stub { // he XML we'd lose the icon. We just remove all dangling files after saving the XML. shortcut.setIconResourceId(0); shortcut.setIconResName(null); - shortcut.clearFlags(ShortcutInfo.FLAG_HAS_ICON_FILE | ShortcutInfo.FLAG_HAS_ICON_RES); + shortcut.clearFlags(ShortcutInfo.FLAG_HAS_ICON_FILE | + ShortcutInfo.FLAG_MASKABLE_BITMAP | ShortcutInfo.FLAG_HAS_ICON_RES); } public void cleanupBitmapsForPackage(@UserIdInt int userId, String packageName) { @@ -1351,7 +1352,8 @@ public class ShortcutService extends IShortcutService.Stub { shortcut.addFlags(ShortcutInfo.FLAG_HAS_ICON_RES); return; } - case Icon.TYPE_BITMAP: { + case Icon.TYPE_BITMAP: + case Icon.TYPE_BITMAP_MASKABLE: { bitmap = icon.getBitmap(); // Don't recycle in this case. break; } @@ -1382,6 +1384,9 @@ public class ShortcutService extends IShortcutService.Stub { shortcut.setBitmapPath(out.getFile().getAbsolutePath()); shortcut.addFlags(ShortcutInfo.FLAG_HAS_ICON_FILE); + if (icon.getType() == Icon.TYPE_BITMAP_MASKABLE) { + shortcut.addFlags(ShortcutInfo.FLAG_MASKABLE_BITMAP); + } } finally { IoUtils.closeQuietly(out); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index a53102f0abbf..122db7e784cc 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -6146,6 +6146,7 @@ public class WindowManagerService extends IWindowManager.Stub * Get an array with display ids ordered by focus priority - last items should be given * focus first. Sparse array just maps position to displayId. */ + // TODO: Maintain display list in focus order in ActivityManager and remove this call. public void getDisplaysInFocusOrder(SparseIntArray displaysInFocusOrder) { synchronized(mWindowMap) { mRoot.getDisplaysInFocusOrder(displaysInFocusOrder); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 2b2bb48c91a3..dd44aa0a53cb 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -244,6 +244,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static final String TAG_INITIALIZATION_BUNDLE = "initialization-bundle"; + private static final String TAG_PASSWORD_TOKEN_HANDLE = "password-token"; + private static final int REQUEST_EXPIRE_PASSWORD = 5571; private static final long MS_PER_DAY = TimeUnit.DAYS.toMillis(1); @@ -506,6 +508,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { boolean mAdminBroadcastPending = false; PersistableBundle mInitBundle = null; + long mPasswordTokenHandle = 0; + public DevicePolicyData(int userHandle) { mUserHandle = userHandle; } @@ -2557,6 +2561,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { out.endTag(null, TAG_INITIALIZATION_BUNDLE); } + if (policy.mPasswordTokenHandle != 0) { + out.startTag(null, TAG_PASSWORD_TOKEN_HANDLE); + out.attribute(null, ATTR_VALUE, + Long.toString(policy.mPasswordTokenHandle)); + out.endTag(null, TAG_PASSWORD_TOKEN_HANDLE); + } + out.endTag(null, "policies"); out.endDocument(); @@ -2763,6 +2774,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { m.symbols = Integer.parseInt(parser.getAttributeValue(null, "symbols")); m.nonLetter = Integer.parseInt(parser.getAttributeValue(null, "nonletter")); } + } else if (TAG_PASSWORD_TOKEN_HANDLE.equals(tag)) { + policy.mPasswordTokenHandle = Long.parseLong( + parser.getAttributeValue(null, ATTR_VALUE)); } else { Slog.w(LOG_TAG, "Unknown tag: " + tag); XmlUtils.skipCurrentTag(parser); @@ -4074,12 +4088,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mInjector.binderRestoreCallingIdentity(token); } } - @Override public boolean resetPassword(String passwordOrNull, int flags) throws RemoteException { - if (!mHasFeature) { - return false; - } final int callingUid = mInjector.binderGetCallingUid(); final int userHandle = mInjector.userHandleGetCallingUserId(); @@ -4090,15 +4100,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { enforceNotManagedProfile(userHandle, "clear the active password"); } - int quality; synchronized (this) { // If caller has PO (or DO) it can change the password, so see if that's the case first. ActiveAdmin admin = getActiveAdminWithPolicyForUidLocked( null, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, callingUid); final boolean preN; if (admin != null) { - preN = getTargetSdk(admin.info.getPackageName(), - userHandle) <= android.os.Build.VERSION_CODES.M; + final int targetSdk = getTargetSdk(admin.info.getPackageName(), userHandle); + if (targetSdk >= Build.VERSION_CODES.O) { + throw new SecurityException("resetPassword() is deprecated for DPC targeting O" + + " or later"); + } + preN = targetSdk <= android.os.Build.VERSION_CODES.M; } else { // Otherwise, make sure the caller has any active admin with the right policy. admin = getActiveAdminForCallerLocked(null, @@ -4149,7 +4162,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return false; } } + } + + return resetPasswordInternal(password, 0, null, flags, callingUid, userHandle); + } + private boolean resetPasswordInternal(String password, long tokenHandle, byte[] token, + int flags, int callingUid, int userHandle) { + int quality; + synchronized (this) { quality = getPasswordQuality(null, userHandle, /* parent */ false); if (quality == DevicePolicyManager.PASSWORD_QUALITY_MANAGED) { quality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; @@ -4239,11 +4260,20 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Don't do this with the lock held, because it is going to call // back in to the service. final long ident = mInjector.binderClearCallingIdentity(); + final boolean result; try { - if (!TextUtils.isEmpty(password)) { - mLockPatternUtils.saveLockPassword(password, null, quality, userHandle); + if (token == null) { + if (!TextUtils.isEmpty(password)) { + mLockPatternUtils.saveLockPassword(password, null, quality, userHandle); + } else { + mLockPatternUtils.clearLock(null, userHandle); + } + result = true; } else { - mLockPatternUtils.clearLock(null, userHandle); + result = mLockPatternUtils.setLockCredentialWithToken(password, + TextUtils.isEmpty(password) ? LockPatternUtils.CREDENTIAL_TYPE_NONE + : LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, + tokenHandle, token, userHandle); } boolean requireEntry = (flags & DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY) != 0; if (requireEntry) { @@ -4260,8 +4290,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } finally { mInjector.binderRestoreCallingIdentity(ident); } - - return true; + return result; } private boolean isLockScreenSecureUnchecked(int userId) { @@ -9092,13 +9121,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } final String deviceOwnerPackageName = mOwners.getDeviceOwnerComponent() .getPackageName(); - final String[] pkgs = mInjector.getPackageManager().getPackagesForUid(callerUid); - - for (String pkg : pkgs) { - if (deviceOwnerPackageName.equals(pkg)) { - return true; + try { + String[] pkgs = mInjector.getIPackageManager().getPackagesForUid(callerUid); + for (String pkg : pkgs) { + if (deviceOwnerPackageName.equals(pkg)) { + return true; + } + } + } catch (RemoteException e) { + return false; } - } } return false; @@ -10621,4 +10653,98 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { enforceDeviceOwnerOrManageUsers(); return getUserData(UserHandle.USER_SYSTEM).mLastNetworkLogsRetrievalTime; } + + @Override + public boolean setResetPasswordToken(ComponentName admin, byte[] token) { + if (!mHasFeature) { + return false; + } + if (token == null || token.length < 32) { + throw new IllegalArgumentException("token must be at least 32-byte long"); + } + synchronized (this) { + final int userHandle = mInjector.userHandleGetCallingUserId(); + getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + + DevicePolicyData policy = getUserData(userHandle); + long ident = mInjector.binderClearCallingIdentity(); + try { + if (policy.mPasswordTokenHandle != 0) { + mLockPatternUtils.removeEscrowToken(policy.mPasswordTokenHandle, userHandle); + } + + policy.mPasswordTokenHandle = mLockPatternUtils.addEscrowToken(token, userHandle); + saveSettingsLocked(userHandle); + return policy.mPasswordTokenHandle != 0; + } finally { + mInjector.binderRestoreCallingIdentity(ident); + } + } + } + + @Override + public boolean clearResetPasswordToken(ComponentName admin) { + if (!mHasFeature) { + return false; + } + synchronized (this) { + final int userHandle = mInjector.userHandleGetCallingUserId(); + getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + + DevicePolicyData policy = getUserData(userHandle); + if (policy.mPasswordTokenHandle != 0) { + long ident = mInjector.binderClearCallingIdentity(); + try { + boolean result = mLockPatternUtils.removeEscrowToken( + policy.mPasswordTokenHandle, userHandle); + policy.mPasswordTokenHandle = 0; + saveSettingsLocked(userHandle); + return result; + } finally { + mInjector.binderRestoreCallingIdentity(ident); + } + } + } + return false; + } + + @Override + public boolean isResetPasswordTokenActive(ComponentName admin) { + synchronized (this) { + final int userHandle = mInjector.userHandleGetCallingUserId(); + getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + + DevicePolicyData policy = getUserData(userHandle); + if (policy.mPasswordTokenHandle != 0) { + long ident = mInjector.binderClearCallingIdentity(); + try { + return mLockPatternUtils.isEscrowTokenActive(policy.mPasswordTokenHandle, + userHandle); + } finally { + mInjector.binderRestoreCallingIdentity(ident); + } + } + } + return false; + } + + @Override + public boolean resetPasswordWithToken(ComponentName admin, String passwordOrNull, byte[] token, + int flags) { + Preconditions.checkNotNull(token); + synchronized (this) { + final int userHandle = mInjector.userHandleGetCallingUserId(); + getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + + DevicePolicyData policy = getUserData(userHandle); + if (policy.mPasswordTokenHandle != 0) { + final String password = passwordOrNull != null ? passwordOrNull : ""; + return resetPasswordInternal(password, policy.mPasswordTokenHandle, token, + flags, mInjector.binderGetCallingUid(), userHandle); + } else { + Slog.w(LOG_TAG, "No saved token handle"); + } + } + return false; + } } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 83e209dd5bba..31c8261d0bec 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -35,6 +35,7 @@ import android.os.FileUtils; import android.os.IIncidentManager; import android.os.Looper; import android.os.PowerManager; +import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.StrictMode; @@ -236,6 +237,8 @@ public final class SystemServer { private static final String START_SENSOR_SERVICE = "StartSensorService"; private Future<?> mSensorServiceStart; + private Future<?> mZygotePreload; + /** * Start the sensor service. This is a blocking call and can take time. @@ -688,6 +691,26 @@ public final class SystemServer { } try { + final String SECONDARY_ZYGOTE_PRELOAD = "SecondaryZygotePreload"; + // We start the preload ~1s before the webview factory preparation, to + // ensure that it completes before the 32 bit relro process is forked + // from the zygote. In the event that it takes too long, the webview + // RELRO process will block, but it will do so without holding any locks. + mZygotePreload = SystemServerInitThreadPool.get().submit(() -> { + try { + Slog.i(TAG, SECONDARY_ZYGOTE_PRELOAD); + BootTimingsTraceLog traceLog = new BootTimingsTraceLog( + SYSTEM_SERVER_TIMING_ASYNC_TAG, Trace.TRACE_TAG_SYSTEM_SERVER); + traceLog.traceBegin(SECONDARY_ZYGOTE_PRELOAD); + if (!Process.zygoteProcess.preloadDefault(Build.SUPPORTED_32_BIT_ABIS[0])) { + Slog.e(TAG, "Unable to preload default resources"); + } + traceLog.traceEnd(); + } catch (Exception ex) { + Slog.e(TAG, "Exception preloading default resources", ex); + } + }, SECONDARY_ZYGOTE_PRELOAD); + traceBeginAndSlog("StartKeyAttestationApplicationIdProviderService"); ServiceManager.addService("sec_key_att_app_id_provider", new KeyAttestationApplicationIdProviderService(context)); @@ -1615,6 +1638,8 @@ public final class SystemServer { BootTimingsTraceLog traceLog = new BootTimingsTraceLog( SYSTEM_SERVER_TIMING_ASYNC_TAG, Trace.TRACE_TAG_SYSTEM_SERVER); traceLog.traceBegin(WEBVIEW_PREPARATION); + ConcurrentUtils.waitForFutureNoInterrupt(mZygotePreload, "Zygote preload"); + mZygotePreload = null; mWebViewUpdateService.prepareWebViewInSystemServer(); traceLog.traceEnd(); }, WEBVIEW_PREPARATION); diff --git a/services/print/java/com/android/server/print/CompanionDeviceManagerService.java b/services/print/java/com/android/server/print/CompanionDeviceManagerService.java index 9824c1d12613..9ac8295e816d 100644 --- a/services/print/java/com/android/server/print/CompanionDeviceManagerService.java +++ b/services/print/java/com/android/server/print/CompanionDeviceManagerService.java @@ -19,20 +19,28 @@ package com.android.server.print; import static com.android.internal.util.Preconditions.checkNotNull; -import android.app.PendingIntent; +import android.Manifest; import android.companion.AssociationRequest; +import android.companion.CompanionDeviceManager; +import android.companion.ICompanionDeviceDiscoveryService; +import android.companion.ICompanionDeviceDiscoveryServiceCallback; import android.companion.ICompanionDeviceManager; -import android.companion.ICompanionDeviceManagerService; -import android.companion.IOnAssociateCallback; +import android.companion.IFindDeviceCallback; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.net.NetworkPolicyManager; import android.os.Binder; import android.os.IBinder; +import android.os.IDeviceIdleController; import android.os.RemoteException; -import android.util.Log; +import android.os.ServiceManager; +import android.util.Slog; +import com.android.internal.util.ArrayUtils; import com.android.server.SystemService; //TODO move to own package! @@ -40,7 +48,8 @@ import com.android.server.SystemService; public class CompanionDeviceManagerService extends SystemService { private static final ComponentName SERVICE_TO_BIND_TO = ComponentName.createRelative( - "com.android.companiondevicemanager", ".DeviceDiscoveryService"); + CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME, + ".DeviceDiscoveryService"); private static final boolean DEBUG = false; private static final String LOG_TAG = "CompanionDeviceManagerService"; @@ -58,14 +67,13 @@ public class CompanionDeviceManagerService extends SystemService { } class CompanionDeviceManagerImpl extends ICompanionDeviceManager.Stub { - @Override public void associate( AssociationRequest request, - IOnAssociateCallback callback, - String callingPackage) throws RemoteException { + IFindDeviceCallback callback, + String callingPackage) { if (DEBUG) { - Log.i(LOG_TAG, "associate(request = " + request + ", callback = " + callback + Slog.i(LOG_TAG, "associate(request = " + request + ", callback = " + callback + ", callingPackage = " + callingPackage + ")"); } checkNotNull(request); @@ -85,23 +93,24 @@ public class CompanionDeviceManagerService extends SystemService { private ServiceConnection getServiceConnection( final AssociationRequest<?> request, - final IOnAssociateCallback callback, + final IFindDeviceCallback findDeviceCallback, final String callingPackage) { return new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { if (DEBUG) { - Log.i(LOG_TAG, + Slog.i(LOG_TAG, "onServiceConnected(name = " + name + ", service = " + service + ")"); } try { - ICompanionDeviceManagerService.Stub + ICompanionDeviceDiscoveryService.Stub .asInterface(service) .startDiscovery( request, - getCallback(callingPackage, callback), - callingPackage); + callingPackage, + findDeviceCallback, + getServiceCallback()); } catch (RemoteException e) { throw new RuntimeException(e); } @@ -109,39 +118,50 @@ public class CompanionDeviceManagerService extends SystemService { @Override public void onServiceDisconnected(ComponentName name) { - if (DEBUG) Log.i(LOG_TAG, "onServiceDisconnected(name = " + name + ")"); + if (DEBUG) Slog.i(LOG_TAG, "onServiceDisconnected(name = " + name + ")"); } }; } - private IOnAssociateCallback.Stub getCallback( - String callingPackage, - IOnAssociateCallback propagateTo) { - return new IOnAssociateCallback.Stub() { - - @Override - public void onSuccess(PendingIntent launcher) - throws RemoteException { - if (DEBUG) Log.i(LOG_TAG, "onSuccess(launcher = " + launcher + ")"); - recordSpecialPriviledgesForPackage(callingPackage); - propagateTo.onSuccess(launcher); - } - + private ICompanionDeviceDiscoveryServiceCallback.Stub getServiceCallback() { + return new ICompanionDeviceDiscoveryServiceCallback.Stub() { @Override - public void onFailure(CharSequence reason) throws RemoteException { - if (DEBUG) Log.i(LOG_TAG, "onFailure()"); - propagateTo.onFailure(reason); + public void onDeviceSelected(String packageName, int userId) { + grantSpecialAccessPermissionsIfNeeded(packageName, userId); } }; } - void recordSpecialPriviledgesForPackage(String priviledgedPackage) { - //TODO Show dialog before recording notification access -// final SettingStringHelper setting = -// new SettingStringHelper( -// getContext().getContentResolver(), -// Settings.Secure.ENABLED_NOTIFICATION_LISTENERS, -// Binder.getCallingUid()); -// setting.write(ColonDelimitedSet.OfStrings.add(setting.read(), priviledgedPackage)); + private void grantSpecialAccessPermissionsIfNeeded(String packageName, int userId) { + final long identity = Binder.clearCallingIdentity(); + final PackageInfo packageInfo; + try { + packageInfo = getContext().getPackageManager().getPackageInfoAsUser( + packageName, PackageManager.GET_PERMISSIONS, userId); + } catch (PackageManager.NameNotFoundException e) { + Slog.e(LOG_TAG, "Error granting special access permissions to package:" + + packageName, e); + return; + } + try { + if (ArrayUtils.contains(packageInfo.requestedPermissions, + Manifest.permission.RUN_IN_BACKGROUND)) { + IDeviceIdleController idleController = IDeviceIdleController.Stub.asInterface( + ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER)); + try { + idleController.addPowerSaveWhitelistApp(packageName); + } catch (RemoteException e) { + /* ignore - local call */ + } + } + if (ArrayUtils.contains(packageInfo.requestedPermissions, + Manifest.permission.USE_DATA_IN_BACKGROUND)) { + NetworkPolicyManager.from(getContext()).addUidPolicy( + packageInfo.applicationInfo.uid, + NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND); + } + } finally { + Binder.restoreCallingIdentity(identity); + } } } diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java index 3a88e9c6303f..c0b79be95da1 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java @@ -117,6 +117,7 @@ public class NetworkScoreServiceTest { private static final String SSID = "ssid"; private static final String SSID_2 = "ssid_2"; private static final String SSID_3 = "ssid_3"; + private static final String INVALID_BSSID = "invalid_bssid"; private static final ComponentName RECOMMENDATION_SERVICE_COMP = new ComponentName("newPackageName", "newScoringServiceClass"); private static final ScoredNetwork SCORED_NETWORK = @@ -778,6 +779,54 @@ public class NetworkScoreServiceTest { } @Test + public void testCurrentNetworkScoreCacheFilter_invalidWifiInfo_nullSsid() throws Exception { + when(mWifiInfo.getSSID()).thenReturn(null); + NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter = + new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> mWifiInfo); + + List<ScoredNetwork> actualList = + cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2)); + + assertTrue(actualList.isEmpty()); + } + + @Test + public void testCurrentNetworkScoreCacheFilter_invalidWifiInfo_noneSsid() throws Exception { + when(mWifiInfo.getSSID()).thenReturn(WifiSsid.NONE); + NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter = + new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> mWifiInfo); + + List<ScoredNetwork> actualList = + cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2)); + + assertTrue(actualList.isEmpty()); + } + + @Test + public void testCurrentNetworkScoreCacheFilter_invalidWifiInfo_emptySsid() throws Exception { + when(mWifiInfo.getSSID()).thenReturn(""); + NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter = + new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> mWifiInfo); + + List<ScoredNetwork> actualList = + cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2)); + + assertTrue(actualList.isEmpty()); + } + + @Test + public void testCurrentNetworkScoreCacheFilter_invalidWifiInfo_invalidBssid() throws Exception { + when(mWifiInfo.getBSSID()).thenReturn(INVALID_BSSID); + NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter = + new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> mWifiInfo); + + List<ScoredNetwork> actualList = + cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2)); + + assertTrue(actualList.isEmpty()); + } + + @Test public void testCurrentNetworkScoreCacheFilter_scoreFiltered() throws Exception { NetworkScoreService.CurrentNetworkScoreCacheFilter cacheFilter = new NetworkScoreService.CurrentNetworkScoreCacheFilter(() -> mWifiInfo); @@ -813,6 +862,24 @@ public class NetworkScoreServiceTest { } @Test + public void testScanResultsScoreCacheFilter_invalidScanResults() throws Exception { + List<ScanResult> invalidScanResults = Lists.newArrayList( + new ScanResult(), + createScanResult("", SCORED_NETWORK.networkKey.wifiKey.bssid), + createScanResult(WifiSsid.NONE, SCORED_NETWORK.networkKey.wifiKey.bssid), + createScanResult(SSID, null), + createScanResult(SSID, INVALID_BSSID) + ); + NetworkScoreService.ScanResultsScoreCacheFilter cacheFilter = + new NetworkScoreService.ScanResultsScoreCacheFilter(() -> invalidScanResults); + + List<ScoredNetwork> actualList = + cacheFilter.apply(Lists.newArrayList(SCORED_NETWORK, SCORED_NETWORK_2)); + + assertTrue(actualList.isEmpty()); + } + + @Test public void testScanResultsScoreCacheFilter_scoresFiltered() throws Exception { NetworkScoreService.ScanResultsScoreCacheFilter cacheFilter = new NetworkScoreService.ScanResultsScoreCacheFilter(() -> mScanResults); diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index a186b5956f4a..23a1bb4462f4 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -56,6 +56,7 @@ import android.util.Pair; import com.android.internal.R; import com.android.internal.util.ParcelableString; +import com.android.internal.widget.LockPatternUtils; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.pm.UserRestrictionsUtils; @@ -3735,6 +3736,41 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm.getPermissionGrantState(admin1, app2, permission)); } + public void testResetPasswordWithToken() throws Exception { + mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; + setupDeviceOwner(); + // test token validation + try { + dpm.setResetPasswordToken(admin1, new byte[31]); + fail("should not have accepted tokens too short"); + } catch (IllegalArgumentException expected) { + } + // test adding a token + final byte[] token = new byte[32]; + final long handle = 123456; + final String password = "password"; + when(mContext.lockPatternUtils.addEscrowToken(eq(token), eq(UserHandle.USER_SYSTEM))) + .thenReturn(handle); + assertTrue(dpm.setResetPasswordToken(admin1, token)); + + // test password activation + when(mContext.lockPatternUtils.isEscrowTokenActive(eq(handle), eq(UserHandle.USER_SYSTEM))) + .thenReturn(true); + assertTrue(dpm.isResetPasswordTokenActive(admin1)); + + // test reset password with token + when(mContext.lockPatternUtils.setLockCredentialWithToken(eq(password), + eq(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD), eq(handle), eq(token), + eq(UserHandle.USER_SYSTEM))) + .thenReturn(true); + assertTrue(dpm.resetPasswordWithToken(admin1, password, token, 0)); + + // test removing a token + when(mContext.lockPatternUtils.removeEscrowToken(eq(handle), eq(UserHandle.USER_SYSTEM))) + .thenReturn(true); + assertTrue(dpm.clearResetPasswordToken(admin1)); + } + private void setUserSetupCompleteForUser(boolean isUserSetupComplete, int userhandle) { when(mContext.settings.settingsSecureGetIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0, userhandle)).thenReturn(isUserSetupComplete ? 1 : 0); diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java index ed6779c41491..43e2610e187a 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java @@ -174,6 +174,8 @@ public abstract class DpmTestBase extends AndroidTestCase { anyInt(), eq(UserHandle.getUserId(packageUid))); + doReturn(new String[] {admin.getPackageName()}).when(mMockContext.ipackageManager) + .getPackagesForUid(eq(packageUid)); // Set up getPackageInfo(). markPackageAsInstalled(admin.getPackageName(), ai, UserHandle.getUserId(packageUid)); } diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java index 980aa2d34c79..0c5316743e6b 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java @@ -75,7 +75,9 @@ import android.content.pm.ShortcutInfo; import android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat; import android.graphics.BitmapFactory; +import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; +import android.graphics.drawable.MaskableIconDrawable; import android.net.Uri; import android.os.Bundle; import android.os.Handler; @@ -244,6 +246,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { final Icon icon1 = Icon.createWithResource(getTestContext(), R.drawable.icon1); final Icon icon2 = Icon.createWithBitmap(BitmapFactory.decodeResource( getTestContext().getResources(), R.drawable.icon2)); + final Icon icon3 = Icon.createWithMaskableBitmap(BitmapFactory.decodeResource( + getTestContext().getResources(), R.drawable.icon2)); final ShortcutInfo si1 = makeShortcut( "shortcut1", @@ -261,12 +265,18 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { icon2, makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class), /* weight */ 12); - final ShortcutInfo si3 = makeShortcut("shortcut3"); + final ShortcutInfo si3 = makeShortcut( + "shortcut3", + "Title 3", + /* activity */ null, + icon3, + makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class), + /* weight */ 13); - assertTrue(mManager.setDynamicShortcuts(list(si1, si2))); + assertTrue(mManager.setDynamicShortcuts(list(si1, si2, si3))); assertShortcutIds(assertAllNotKeyFieldsOnly( mManager.getDynamicShortcuts()), - "shortcut1", "shortcut2"); + "shortcut1", "shortcut2", "shortcut3"); assertEquals(2, mManager.getRemainingCallCount()); // TODO: Check fields @@ -550,7 +560,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource( getTestContext().getResources(), R.drawable.black_32x32)); - final Icon bmp64x64 = Icon.createWithBitmap(BitmapFactory.decodeResource( + final Icon bmp64x64_maskable = Icon.createWithMaskableBitmap(BitmapFactory.decodeResource( getTestContext().getResources(), R.drawable.black_64x64)); final Icon bmp512x512 = Icon.createWithBitmap(BitmapFactory.decodeResource( getTestContext().getResources(), R.drawable.black_512x512)); @@ -561,7 +571,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { makeShortcutWithIcon("res32x32", res32x32), makeShortcutWithIcon("res64x64", res64x64), makeShortcutWithIcon("bmp32x32", bmp32x32), - makeShortcutWithIcon("bmp64x64", bmp64x64), + makeShortcutWithIcon("bmp64x64", bmp64x64_maskable), makeShortcutWithIcon("bmp512x512", bmp512x512), makeShortcut("none") ))); @@ -691,6 +701,15 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { bmp = pfdToBitmap( mLauncherApps.getShortcutIconFd(CALLING_PACKAGE_1, "bmp32x32", HANDLE_USER_P0)); assertBitmapSize(128, 128, bmp); + + Drawable dr = mLauncherApps.getShortcutIconDrawable( + makeShortcutWithIcon("bmp64x64", bmp64x64_maskable), 0); + assertTrue(dr instanceof MaskableIconDrawable); + float viewportPercentage = 1 / (1 + 2 * MaskableIconDrawable.getExtraInsetPercentage()); + assertEquals((int) (bmp64x64_maskable.getBitmap().getWidth() * viewportPercentage), + dr.getIntrinsicWidth()); + assertEquals((int) (bmp64x64_maskable.getBitmap().getHeight() * viewportPercentage), + dr.getIntrinsicHeight()); } public void testCleanupDanglingBitmaps() throws Exception { diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java index 562de4148bb1..28ec4fd27ccc 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java @@ -932,6 +932,74 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { dumpUserFile(USER_10); } + public void testShortcutInfoSaveAndLoad_maskableBitmap() throws InterruptedException { + mRunningUsers.put(USER_10, true); + + setCaller(CALLING_PACKAGE_1, USER_10); + + final Icon bmp32x32 = Icon.createWithMaskableBitmap(BitmapFactory.decodeResource( + getTestContext().getResources(), R.drawable.black_32x32)); + + PersistableBundle pb = new PersistableBundle(); + pb.putInt("k", 1); + ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext) + .setId("id") + .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class)) + .setIcon(bmp32x32) + .setTitle("title") + .setText("text") + .setDisabledMessage("dismes") + .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz")) + .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val")) + .setRank(123) + .setExtras(pb) + .build(); + sorig.setTimestamp(mInjectedCurrentTimeMillis); + + mManager.addDynamicShortcuts(list(sorig)); + + mInjectedCurrentTimeMillis += 1; + final long now = mInjectedCurrentTimeMillis; + mInjectedCurrentTimeMillis += 1; + + dumpsysOnLogcat("before save"); + + // Save and load. + mService.saveDirtyInfo(); + initService(); + mService.handleUnlockUser(USER_10); + + dumpUserFile(USER_10); + dumpsysOnLogcat("after load"); + + ShortcutInfo si; + si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_10); + + assertEquals(USER_10, si.getUserId()); + assertEquals(HANDLE_USER_10, si.getUserHandle()); + assertEquals(CALLING_PACKAGE_1, si.getPackage()); + assertEquals("id", si.getId()); + assertEquals(ShortcutActivity2.class.getName(), si.getActivity().getClassName()); + assertEquals(null, si.getIcon()); + assertEquals("title", si.getTitle()); + assertEquals("text", si.getText()); + assertEquals("dismes", si.getDisabledMessage()); + assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories()); + assertEquals("action", si.getIntent().getAction()); + assertEquals("val", si.getIntent().getStringExtra("key")); + assertEquals(0, si.getRank()); + assertEquals(1, si.getExtras().getInt("k")); + + assertEquals(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_HAS_ICON_FILE + | ShortcutInfo.FLAG_STRINGS_RESOLVED | ShortcutInfo.FLAG_MASKABLE_BITMAP, + si.getFlags()); + assertNotNull(si.getBitmapPath()); // Something should be set. + assertEquals(0, si.getIconResourceId()); + assertTrue(si.getLastChangedTimestamp() < now); + + dumpUserFile(USER_10); + } + public void testShortcutInfoSaveAndLoad_resId() throws InterruptedException { mRunningUsers.put(USER_10, true); diff --git a/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java b/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java index d71cc6f7ddf0..6e3a8e879306 100644 --- a/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java +++ b/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java @@ -50,6 +50,7 @@ import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.LruCache; import android.util.TypedValue; +import android.view.DisplayAdjustments; import android.view.ViewGroup.LayoutParams; import java.io.File; @@ -71,7 +72,8 @@ public class Resources_Delegate { DisplayMetrics metrics, Configuration config, LayoutlibCallback layoutlibCallback) { - Resources resources = new Resources(assets, metrics, config); + Resources resources = new Resources(Resources_Delegate.class.getClassLoader()); + resources.setImpl(new ResourcesImpl(assets, metrics, config, new DisplayAdjustments())); resources.mContext = context; resources.mLayoutlibCallback = layoutlibCallback; return Resources.mSystem = resources; diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java index bae2dc0c25f5..8ebfc659bbe7 100644 --- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java +++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java @@ -132,7 +132,11 @@ public class LayoutLibTestCallback extends LayoutlibCallback { @Override public Integer getResourceId(ResourceType type, String name) { - return mResources.get(type).get(name); + Map<String, Integer> resName2Id = mResources.get(type); + if (resName2Id == null) { + return null; + } + return resName2Id.get(name); } @Override diff --git a/tools/layoutlib/create/create.iml b/tools/layoutlib/create/create.iml index 368b46bc92dc..ac975026fc9b 100644 --- a/tools/layoutlib/create/create.iml +++ b/tools/layoutlib/create/create.iml @@ -12,9 +12,9 @@ <orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" /> <orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="module-library"> - <library name="asm-5.0"> + <library name="asm-5.2"> <CLASSES> - <root url="jar://$MODULE_DIR$/../../../../../prebuilts/misc/common/asm/asm-5.0.jar!/" /> + <root url="jar://$MODULE_DIR$/../../../../../prebuilts/misc/common/asm/asm-5.2.jar!/" /> </CLASSES> <JAVADOC /> <SOURCES> diff --git a/tools/preload2/src/com/android/preload/DeviceUtils.java b/tools/preload2/src/com/android/preload/DeviceUtils.java index 803a7f195a59..18cab7bee12d 100644 --- a/tools/preload2/src/com/android/preload/DeviceUtils.java +++ b/tools/preload2/src/com/android/preload/DeviceUtils.java @@ -16,13 +16,18 @@ package com.android.preload; +import com.android.ddmlib.AdbCommandRejectedException; import com.android.ddmlib.AndroidDebugBridge; import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener; import com.android.preload.classdataretrieval.hprof.Hprof; import com.android.ddmlib.DdmPreferences; import com.android.ddmlib.IDevice; import com.android.ddmlib.IShellOutputReceiver; +import com.android.ddmlib.SyncException; +import com.android.ddmlib.TimeoutException; +import java.io.File; +import java.io.IOException; import java.util.Date; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; @@ -32,6 +37,18 @@ import java.util.concurrent.TimeUnit; */ public class DeviceUtils { + // Locations + private static final String PRELOADED_CLASSES_FILE = "/etc/preloaded-classes"; + // Shell commands + private static final String CREATE_EMPTY_PRELOADED_CMD = "touch " + PRELOADED_CLASSES_FILE; + private static final String DELETE_CACHE_CMD = "rm /data/dalvik-cache/*/*boot.art"; + private static final String DELETE_PRELOADED_CMD = "rm " + PRELOADED_CLASSES_FILE; + private static final String READ_PRELOADED_CMD = "cat " + PRELOADED_CLASSES_FILE; + private static final String START_SHELL_CMD = "start"; + private static final String STOP_SHELL_CMD = "stop"; + private static final String REMOUNT_SYSTEM_CMD = "mount -o rw,remount /system"; + private static final String UNSET_BOOTCOMPLETE_CMD = "setprop dev.bootcomplete \"0\""; + public static void init(int debugPort) { DdmPreferences.setSelectedDebugPort(debugPort); @@ -119,43 +136,56 @@ public class DeviceUtils { return !ret.contains("No such file or directory"); } - /** - * Remove files involved in a standard build that interfere with collecting data. This will - * remove /etc/preloaded-classes, which determines which classes are allocated already in the - * boot image. It also deletes any compiled boot image on the device. Then it restarts the - * device. - * - * This is a potentially long-running operation, as the boot after the deletion may take a while. - * The method will abort after the given timeout. - */ - public static boolean removePreloaded(IDevice device, long preloadedWaitTimeInSeconds) { - String oldContent = - DeviceUtils.doShellReturnString(device, "cat /etc/preloaded-classes", 1, TimeUnit.SECONDS); - if (oldContent.trim().equals("")) { - System.out.println("Preloaded-classes already empty."); - return true; - } - - // Stop the system server etc. - doShell(device, "stop", 100, TimeUnit.MILLISECONDS); - - // Remount /system, delete /etc/preloaded-classes. It would be nice to use "adb remount," - // but AndroidDebugBridge doesn't expose it. - doShell(device, "mount -o remount,rw /system", 500, TimeUnit.MILLISECONDS); - doShell(device, "rm /etc/preloaded-classes", 100, TimeUnit.MILLISECONDS); - // We do need an empty file. - doShell(device, "touch /etc/preloaded-classes", 100, TimeUnit.MILLISECONDS); - - // Delete the files in the dalvik cache. - doShell(device, "rm /data/dalvik-cache/*/*boot.art", 500, TimeUnit.MILLISECONDS); - - // We'll try to use dev.bootcomplete to know when the system server is back up. But stop - // doesn't reset it, so do it manually. - doShell(device, "setprop dev.bootcomplete \"0\"", 500, TimeUnit.MILLISECONDS); + /** + * Write over the preloaded-classes file with an empty or existing file and regenerate the boot + * image as necessary. + * + * @param device + * @param pcFile + * @param bootTimeout + * @throws AdbCommandRejectedException + * @throws IOException + * @throws TimeoutException + * @throws SyncException + * @return true if successfully overwritten, false otherwise + */ + public static boolean overwritePreloaded(IDevice device, File pcFile, long bootTimeout) + throws AdbCommandRejectedException, IOException, TimeoutException, SyncException { + boolean writeEmpty = (pcFile == null); + if (writeEmpty) { + // Check if the preloaded-classes file is already empty. + String oldContent = + doShellReturnString(device, READ_PRELOADED_CMD, 1, TimeUnit.SECONDS); + if (oldContent.trim().equals("")) { + System.out.println("Preloaded-classes already empty."); + return true; + } + } - // Start the system server. - doShell(device, "start", 100, TimeUnit.MILLISECONDS); + // Stop the system server etc. + doShell(device, STOP_SHELL_CMD, 1, TimeUnit.SECONDS); + // Remount the read-only system partition + doShell(device, REMOUNT_SYSTEM_CMD, 1, TimeUnit.SECONDS); + // Delete the preloaded-classes file + doShell(device, DELETE_PRELOADED_CMD, 1, TimeUnit.SECONDS); + // Delete the dalvik cache files + doShell(device, DELETE_CACHE_CMD, 1, TimeUnit.SECONDS); + if (writeEmpty) { + // Write an empty preloaded-classes file + doShell(device, CREATE_EMPTY_PRELOADED_CMD, 500, TimeUnit.MILLISECONDS); + } else { + // Push the new preloaded-classes file + device.pushFile(pcFile.getAbsolutePath(), PRELOADED_CLASSES_FILE); + } + // Manually reset the boot complete flag + doShell(device, UNSET_BOOTCOMPLETE_CMD, 1, TimeUnit.SECONDS); + // Restart system server on the device + doShell(device, START_SHELL_CMD, 1, TimeUnit.SECONDS); + // Wait for the boot complete flag and return the outcome. + return waitForBootComplete(device, bootTimeout); + } + private static boolean waitForBootComplete(IDevice device, long timeout) { // Do a loop checking each second whether bootcomplete. Wait for at most the given // threshold. Date startDate = new Date(); @@ -178,7 +208,7 @@ public class DeviceUtils { Date endDate = new Date(); long seconds = TimeUnit.SECONDS.convert(endDate.getTime() - startDate.getTime(), TimeUnit.MILLISECONDS); - if (seconds > preloadedWaitTimeInSeconds) { + if (seconds > timeout) { return false; } } diff --git a/tools/preload2/src/com/android/preload/Main.java b/tools/preload2/src/com/android/preload/Main.java index c42a19b58811..2265e9557c4b 100644 --- a/tools/preload2/src/com/android/preload/Main.java +++ b/tools/preload2/src/com/android/preload/Main.java @@ -29,6 +29,7 @@ import com.android.preload.actions.RunMonkeyAction; import com.android.preload.actions.ScanAllPackagesAction; import com.android.preload.actions.ScanPackageAction; import com.android.preload.actions.ShowDataAction; +import com.android.preload.actions.WritePreloadedClassesAction; import com.android.preload.classdataretrieval.ClassDataRetriever; import com.android.preload.classdataretrieval.hprof.Hprof; import com.android.preload.classdataretrieval.jdwp.JDWPClassDataRetriever; @@ -96,6 +97,7 @@ public class Main { public final static String COMPUTE_FILE_CMD = "comp"; public final static String EXPORT_CMD = "export"; public final static String IMPORT_CMD = "import"; + public final static String WRITE_CMD = "write"; /** * @param args @@ -132,6 +134,7 @@ public class Main { null)); actions.add(new ComputeThresholdXAction("Compute(X)", dataTableModel, CLASS_PRELOAD_BLACKLIST)); + actions.add(new WritePreloadedClassesAction(clientUtils, null, dataTableModel)); actions.add(new ShowDataAction(dataTableModel)); actions.add(new ImportAction(dataTableModel)); actions.add(new ExportAction(dataTableModel)); @@ -200,6 +203,11 @@ public class Main { ui.input(it.next()); ui.confirmYes(); ui.output(new File(it.next())); + // Operation: Write preloaded classes from a specific file + } else if (WRITE_CMD.equals(op)) { + System.out.println("Writing preloaded classes."); + ui.action(WritePreloadedClassesAction.class); + ui.input(new File(it.next())); } } } catch (NoSuchElementException e) { @@ -305,8 +313,16 @@ public class Main { Main.getUI().showMessageDialog("The device will reboot. This will potentially take a " + "long time. Please be patient."); - if (!DeviceUtils.removePreloaded(device, 15 * 60) /* 15m timeout */) { - Main.getUI().showMessageDialog("Removing preloaded-classes failed unexpectedly!"); + boolean success = false; + try { + success = DeviceUtils.overwritePreloaded(device, null, 15 * 60); + } catch (Exception e) { + System.err.println(e); + } finally { + if (!success) { + Main.getUI().showMessageDialog( + "Removing preloaded-classes failed unexpectedly!"); + } } } } diff --git a/tools/preload2/src/com/android/preload/actions/WritePreloadedClassesAction.java b/tools/preload2/src/com/android/preload/actions/WritePreloadedClassesAction.java new file mode 100644 index 000000000000..9b97f1168df9 --- /dev/null +++ b/tools/preload2/src/com/android/preload/actions/WritePreloadedClassesAction.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2015 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.preload.actions; + +import com.android.ddmlib.Client; +import com.android.ddmlib.IDevice; +import com.android.preload.ClientUtils; +import com.android.preload.DeviceUtils; +import com.android.preload.DumpData; +import com.android.preload.DumpTableModel; +import com.android.preload.Main; + +import java.awt.event.ActionEvent; +import java.io.File; +import java.util.Date; +import java.util.Map; + +public class WritePreloadedClassesAction extends AbstractThreadedDeviceSpecificAction { + private File preloadedClassFile; + + public WritePreloadedClassesAction(ClientUtils utils, IDevice device, DumpTableModel dataTableModel) { + super("Write preloaded classes action", device); + } + + @Override + public void actionPerformed(ActionEvent e) { + File[] files = Main.getUI().showOpenDialog(true); + if (files != null && files.length > 0) { + preloadedClassFile = files[0]; + super.actionPerformed(e); + } + } + + @Override + public void run() { + Main.getUI().showWaitDialog(); + try { + // Write the new file with a 5-minute timeout + DeviceUtils.overwritePreloaded(device, preloadedClassFile, 5 * 60); + } catch (Exception e) { + System.err.println(e); + } finally { + Main.getUI().hideWaitDialog(); + } + } +} |