Merge "Add URL on ViewStructure."
diff --git a/Android.mk b/Android.mk
index 28adbca..7a8b1b7 100644
--- a/Android.mk
+++ b/Android.mk
@@ -295,9 +295,9 @@
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 b00628d..7465c4d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -121,6 +121,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 2a3327e..25b393c 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -211,6 +211,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 5bf2f6b..2c2831f 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -121,6 +121,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 7015381..b336472 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.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 @@
// 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 0263681..7d039ef 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -1802,7 +1802,7 @@
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 e0fdac1..49cd2c6 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -80,7 +80,7 @@
/* 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 fb927e9..6dd31a8 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -357,7 +357,8 @@
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 @@
// 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 @@
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 @@
/**
* 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 @@
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 @@
/**
* 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 @@
* @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 f1ccabe..0eb47a3 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -28,6 +28,7 @@
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 @@
* 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 @@
}
/**
+ * 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 79fe10e..c2f75c8 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -342,4 +342,9 @@
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 b379c7c..c0c1a4d 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -29,12 +29,10 @@
/**
* 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 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 @@
/**
* 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 @@
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
similarity index 71%
rename from core/java/android/companion/ICompanionDeviceManagerService.aidl
rename to core/java/android/companion/ICompanionDeviceDiscoveryService.aidl
index ff2a7eb..4d77963 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
similarity index 81%
rename from core/java/android/companion/ICompanionDeviceManagerServiceCallback.aidl
rename to core/java/android/companion/ICompanionDeviceDiscoveryServiceCallback.aidl
index c9dd345..7af708e 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 065e31be..1d30ada 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 @@
*/
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
similarity index 95%
rename from core/java/android/companion/IOnAssociateCallback.aidl
rename to core/java/android/companion/IFindDeviceCallback.aidl
index 4867eadd..919e1519 100644
--- a/core/java/android/companion/IOnAssociateCallback.aidl
+++ b/core/java/android/companion/IFindDeviceCallback.aidl
@@ -19,7 +19,7 @@
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 028a7bcf..b0505ac 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -669,13 +669,14 @@
* 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 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 c8f6406..40deeae 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -37,6 +37,7 @@
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 @@
}
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 @@
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 b4dcdf7..f1f2683 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -92,6 +92,9 @@
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 @@
FLAG_DISABLED,
FLAG_STRINGS_RESOLVED,
FLAG_IMMUTABLE,
+ FLAG_MASKABLE_BITMAP,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ShortcutFlags {}
@@ -690,6 +694,7 @@
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 @@
* <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 @@
}
/**
+ * 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 acb1d07..719a957 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2998,8 +2998,8 @@
*
* 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 @@
* 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 @@
}
/**
- * 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 e5f0bf0..31a74dc 100644
--- a/core/java/android/net/NetworkKey.java
+++ b/core/java/android/net/NetworkKey.java
@@ -24,6 +24,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import android.util.Log;
import java.util.Objects;
@@ -41,6 +42,8 @@
// 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 @@
/**
* 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 @@
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 11b9606..ee8eed1 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -348,8 +348,8 @@
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 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 2dfba28..9ecc6389 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6628,6 +6628,14 @@
"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 b6d720d..83810b0 100644
--- a/core/java/android/text/Emoji.java
+++ b/core/java/android/text/Emoji.java
@@ -164,6 +164,8 @@
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 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 90559dc..5f0a46d 100644
--- a/core/java/android/text/method/BaseKeyListener.java
+++ b/core/java/android/text/method/BaseKeyListener.java
@@ -145,8 +145,11 @@
// 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 @@
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 @@
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 2129039..5f55bdc 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -1008,7 +1008,6 @@
* </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 d195c88..9ce23e6 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -25,7 +25,8 @@
/**
* 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 @@
* 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 @@
*
* @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 @@
*
* @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 fcb4c7b..3d012bf 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -109,6 +109,10 @@
// 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 @@
return mAllowInDataUsageSave;
}
+ public ArraySet<String> getAllowUnthrottledLocation() {
+ return mAllowUnthrottledLocation;
+ }
+
public ArraySet<String> getLinkedApps() {
return mLinkedApps;
}
@@ -446,6 +454,17 @@
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 cd02fbb..97fbfa5 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 72a2e43..fcb0e08 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 2309866..8faa76c 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 1324e38..0d63a1e 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 1afe9da..fff23a0 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.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 @@
@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 @@
}
@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 @@
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 a260e94..864b48a 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 @@
// 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 @@
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 1990fd0..839d380 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 @@
// 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 @@
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 4b4e7af..f005d7b 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 85c3c1c..5008a5f 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -640,6 +640,8 @@
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 @@
mOnSubtitleDataListener = null;
// Modular DRM clean up
+ mOnDrmConfigListener = null;
mOnDrmInfoHandlerDelegate = null;
mOnDrmPreparedHandlerDelegate = null;
resetDrmState();
@@ -3171,7 +3174,7 @@
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 @@
* 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 @@
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 @@
* @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 @@
// 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 @@
// 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 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 @@
@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 @@
}
- @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 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 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 @@
}
- @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 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 @@
@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 @@
}
}
+
+ 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 @@
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 @@
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 @@
}
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 @@
}
mediaPlayer.mDrmProvisioningInProgress = false;
mediaPlayer.mPrepareDrmInProgress = false;
+ if (!succeeded) {
+ cleanDrmObj(); // cleaning up if it hasn't gone through
+ }
}
finished = true;
@@ -4714,24 +4814,18 @@
// 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 @@
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 @@
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 @@
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 @@
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 c941766..636727e 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 @@
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 @@
{
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 @@
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 @@
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 @@
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,211 +1366,10 @@
jniThrowException(
env,
"java/lang/IllegalStateException",
- "The player is not prepared yet.");
+ "Can not release DRM in an active player state.");
}
}
}
-
-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;
- }
- }
-
- 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 @@
"(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 acee5dd..3831cf7 100644
--- a/obex/javax/obex/ServerSession.java
+++ b/obex/javax/obex/ServerSession.java
@@ -658,6 +658,11 @@
*/
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 8a970da..25127ef 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.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
-import android.widget.Toast;
public class DeviceChooserActivity extends Activity {
@@ -129,12 +128,9 @@
}
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 ccbee2a..11c722d 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.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 @@
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 @@
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 @@
//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 0ec16ae2..9ac4d2d 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 @@
}
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 499b6ae..136f17e 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 edcb9b5..d5787e6 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 @@
}
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 d4c7c7a..2e115ab 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 17d0a09..12d0c03 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -133,10 +133,12 @@
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 9c3bd3a..64bbff0 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 918c61c..3001ad9 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 d6abc47..acae9f5 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 9581437..f1f0df0 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 02bd31a..583753a 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 8ff1d1e..00427cb 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 a093b87..8d1f9e4 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 6988c76..080f553 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 3e8e72a..78d4bdd 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 2102e07..40d4d6f 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 77de9a2..b825cfb 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 c354811..85f12b5 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 80d4a26..1f58d4c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -595,6 +595,10 @@
}
}
+ 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 f821308..bda4c95 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -65,6 +65,7 @@
private SettingObserver mSettingObserver;
private int mTextColor;
private int mLevel;
+ private boolean mForceShowPercent;
public BatteryMeterView(Context context) {
this(context, null, 0);
@@ -103,6 +104,11 @@
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 @@
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 19ae295..b9ae585 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -49,6 +49,7 @@
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 7c15096..b3a0eb7 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 @@
@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 6a868d5..c9eb790 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 @@
return mState;
}
+ /** Requests the PowerManager to wake up now. */
+ public void wakeUp() {
+ mDozeService.requestWakeUp();
+ }
+
private boolean isExecutingTransition() {
return !mQueuedRequests.isEmpty();
}
@@ -300,5 +305,8 @@
/** 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 6186df1..e55a597 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 @@
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 db5a392..b5c7dd3 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 @@
}
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 e8c0050..d832810 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 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 @@
* 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 @@
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 @@
private Runnable mShowDismissAffordance = new Runnable() {
@Override
public void run() {
- if (mEnableDragToDismiss) {
+ if (ENABLE_DRAG_TO_DISMISS) {
mDismissViewController.showDismissTarget(mMotionHelper.getBounds());
}
}
@@ -183,23 +179,6 @@
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 @@
@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 @@
mSavedSnapFraction = -1f;
}
- if (touchState.startedDragging() && mEnableDragToDismiss) {
+ if (touchState.startedDragging() && ENABLE_DRAG_TO_DISMISS) {
mHandler.removeCallbacks(mShowDismissAffordance);
mDismissViewController.showDismissTarget(mMotionHelper.getBounds());
}
@@ -469,7 +448,7 @@
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 @@
@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 @@
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 a231e79..3559257 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 @@
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 c85f83b..e0d1cba 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 @@
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 @@
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 @@
// 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 @@
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 @@
// 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 1569b0c..e8d5ece 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 @@
}
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 0e04d0a..c750fdc 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 @@
// 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 @@
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 232941d..428fe9b 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 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.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 @@
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 @@
}
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 @@
}
@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 8227f8f..f7bfc1e 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 @@
}
@Override
- protected void handleSecondaryClick() {
- showDetail(true);
- }
-
- @Override
public CharSequence getTileLabel() {
return mContext.getString(R.string.battery);
}
@@ -118,7 +113,6 @@
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 b48b829..3c28f76 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 @@
@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 a6fe0ea..c9debb2 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.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.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 @@
// 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 @@
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 @@
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 11b5984..12c10df 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.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 @@
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 @@
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 @@
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 @@
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 3648a06..cb4306f 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 @@
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 d599ec1..bc992d8 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 @@
private KeyguardUpdateMonitorCallback mUpdateMonitor;
private final DevicePolicyManager mDevicePolicyManager;
+ private boolean mDozing;
public KeyguardIndicationController(Context context, ViewGroup indicationArea,
LockIcon lockIcon) {
@@ -139,7 +140,7 @@
return;
}
- if (mDevicePolicyManager.isDeviceManaged()) {
+ if (!mDozing && mDevicePolicyManager.isDeviceManaged()) {
final CharSequence organizationName =
mDevicePolicyManager.getDeviceOwnerOrganizationName();
if (organizationName != null) {
@@ -224,6 +225,18 @@
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 void setDozing(boolean dozing) {
+ mDozing = dozing;
+ updateIndication();
+ updateDisclosure();
+ }
+
protected class BaseKeyguardCallback extends KeyguardUpdateMonitorCallback {
private int mLastSuccessiveErrorMessage = -1;
@@ -349,7 +368,8 @@
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 0e074c7..883a66b 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 @@
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 @@
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 @@
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 2b335f4..8f63d45 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 @@
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 @@
// 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 @@
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 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 5da3a10..6da9e90 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 @@
.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 @@
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 457ed6c..ade1b0b 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.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.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 @@
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 @@
private boolean mShowFullAlarm;
private float mDateTimeTranslation;
- private TextView mBatteryLevel;
private SparseBooleanArray mRoamingsBySubId = new SparseBooleanArray();
private boolean mIsRoaming;
@@ -161,8 +158,6 @@
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 @@
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 @@
}
}
- @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 cfbcf8c..3d6e4b3 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 @@
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 c3948258..32afee9 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 @@
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 d12fc2c..c1e7fe4 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 boolean finished;
public int screenState;
+ public boolean requestedWakeup;
public DozeServiceFake() {
reset();
@@ -41,4 +42,9 @@
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 245bf9e..8d2f0c3 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3410,6 +3410,25 @@
// 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 719a64e..fe0b840 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -4166,7 +4166,7 @@
}
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 dc987fa..e6f6e57 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -901,7 +901,8 @@
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 @@
@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 @@
@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 42eb958..ef7780c 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -19,6 +19,7 @@
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 @@
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 @@
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 @@
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
updateUserProfiles(mCurrentUserId);
+ updateThrottlingWhitelistLocked();
+
// prepare providers
loadProvidersLocked();
updateProvidersLocked();
@@ -380,14 +381,7 @@
@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 @@
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 @@
}
}
- for (String whitelistedPackage : mBackgroundThrottlePackageWhitelist) {
- if (receiver.mPackageName.equals(whitelistedPackage)) {
- return true;
- }
- }
-
return false;
}
@@ -2999,6 +3002,13 @@
}
}
+ 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 3e89852..b33538cb 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -603,7 +603,10 @@
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 fbc4440..5c8024a 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 @@
}
@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 a73eb18..c2c24b3 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 @@
// 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 7c24604..f75ce25 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 @@
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 @@
// 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 95734a4..4a29872 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 @@
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 @@
}
// 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 @@
// 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 7cb223d..1337046 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 @@
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 17b005d..8bc72de 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 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 @@
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 98177fe..407262b 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 @@
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 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 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 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 @@
}
mPriorityStack.removeSession(session);
- mAllSessions.remove(session);
try {
session.getCallback().asBinder().unlinkToDeath(session, 0);
@@ -455,7 +456,6 @@
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 @@
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 9da94b3..06b6f66 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.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 @@
&& 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 db712ae..b589057 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 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 @@
// 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 0d63f72..f43e468 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 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 @@
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 3085c9c..570259b 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 @@
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 d8857b7..057e781 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 @@
// 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 @@
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 @@
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 a53102f..122db7e 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 @@
* 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 2b2bb48..dd44aa0 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 @@
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 @@
boolean mAdminBroadcastPending = false;
PersistableBundle mInitBundle = null;
+ long mPasswordTokenHandle = 0;
+
public DevicePolicyData(int userHandle) {
mUserHandle = userHandle;
}
@@ -2557,6 +2561,13 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
} finally {
mInjector.binderRestoreCallingIdentity(ident);
}
-
- return true;
+ return result;
}
private boolean isLockScreenSecureUnchecked(int userId) {
@@ -9092,13 +9121,16 @@
}
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 @@
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 83e209d..31c8261 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -35,6 +35,7 @@
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 @@
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 @@
}
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 @@
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 9824c1d..9ac8295 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 @@
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 @@
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 @@
}
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 @@
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 @@
@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() {
-
+ private ICompanionDeviceDiscoveryServiceCallback.Stub getServiceCallback() {
+ return new ICompanionDeviceDiscoveryServiceCallback.Stub() {
@Override
- public void onSuccess(PendingIntent launcher)
- throws RemoteException {
- if (DEBUG) Log.i(LOG_TAG, "onSuccess(launcher = " + launcher + ")");
- recordSpecialPriviledgesForPackage(callingPackage);
- propagateTo.onSuccess(launcher);
- }
-
- @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 3a88e9c..c0b79be 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 @@
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 @@
}
@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 @@
}
@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 a186b59..23a1bb4 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 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 @@
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 ed6779c..43e2610 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 @@
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 980aa2d..0c53167 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.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 @@
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 @@
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 @@
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 @@
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 @@
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 562de414..28ec4fd 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 @@
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 d71cc6f..6e3a8e8 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.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 @@
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 bae2dc0c..8ebfc65 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 @@
@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 368b46b..ac97502 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 803a7f1..18cab7b 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 @@
*/
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 @@
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;
- }
+ /**
+ * 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;
+ }
+ }
- // Stop the system server etc.
- doShell(device, "stop", 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);
+ }
- // 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);
-
- // Start the system server.
- doShell(device, "start", 100, TimeUnit.MILLISECONDS);
-
+ 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 @@
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 c42a19b..2265e95 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.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 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 @@
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 @@
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 @@
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 0000000..9b97f11
--- /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();
+ }
+ }
+}