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