Merge "Make Dismiss Icon under Cards show up only when focused." into nyc-dev
diff --git a/api/current.txt b/api/current.txt
index 61345fd..00a2b7a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -29146,7 +29146,6 @@
field public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; // 0x1
field public static final deprecated int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
field public static final deprecated int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
- field public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 256; // 0x100
}
public final class PowerManager.WakeLock {
@@ -30331,7 +30330,7 @@
package android.printservice {
- public class CustomPrinterIconCallback {
+ public final class CustomPrinterIconCallback {
method public boolean onCustomPrinterIconLoaded(android.graphics.drawable.Icon);
}
@@ -43630,6 +43629,7 @@
method public void setSharedElementsUseOverlay(boolean);
method public void setSoftInputMode(int);
method public abstract void setStatusBarColor(int);
+ method public void setSustainedPerformanceMode(boolean);
method public abstract void setTitle(java.lang.CharSequence);
method public abstract deprecated void setTitleColor(int);
method public void setTransitionBackgroundFadeDuration(long);
@@ -58086,6 +58086,7 @@
method public java.lang.Object clone();
method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
+ method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
}
public class IllegalFormatCodePointException extends java.util.IllegalFormatException {
@@ -59068,6 +59069,8 @@
method public java.util.NavigableSet<K> navigableKeySet();
method public java.util.Map.Entry<K, V> pollFirstEntry();
method public java.util.Map.Entry<K, V> pollLastEntry();
+ method public boolean replace(K, V, V);
+ method public V replace(K, V);
method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
method public java.util.NavigableMap<K, V> subMap(K, boolean, K, boolean);
method public java.util.SortedMap<K, V> subMap(K, K);
diff --git a/api/system-current.txt b/api/system-current.txt
index d44e157..f017bb0 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -26021,23 +26021,24 @@
}
public final class CaptivePortalStateChangeEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
- ctor public CaptivePortalStateChangeEvent(int);
+ ctor public CaptivePortalStateChangeEvent(int, int);
ctor public CaptivePortalStateChangeEvent(android.os.Parcel);
method public int describeContents();
- method public static void logEvent(int);
+ method public static void logEvent(int, int);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.metrics.CaptivePortalStateChangeEvent> CREATOR;
field public static final int NETWORK_MONITOR_CONNECTED = 0; // 0x0
field public static final int NETWORK_MONITOR_DISCONNECTED = 1; // 0x1
field public static final int NETWORK_MONITOR_VALIDATED = 2; // 0x2
+ field public final int netId;
field public final int state;
}
- public final class ConnectivityServiceChangeEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
+ public final class DefaultNetworkEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
method public int describeContents();
method public static void logEvent(int, int[], int, boolean, boolean);
method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.net.metrics.ConnectivityServiceChangeEvent> CREATOR;
+ field public static final android.os.Parcelable.Creator<android.net.metrics.DefaultNetworkEvent> CREATOR;
field public final int netId;
field public final boolean prevIPv4;
field public final boolean prevIPv6;
@@ -26111,12 +26112,16 @@
field public static final int IPCE_IPMGR_PROVISIONING_FAIL = 4097; // 0x1001
field public static final int IPCE_IPMGR_PROVISIONING_OK = 4096; // 0x1000
field public static final int IPCE_IPRM_BASE = 0; // 0x0
- field public static final int IPCE_IPRM_MESSAGE_RECEIVED = 1; // 0x1
- field public static final int IPCE_IPRM_PROBE_RESULT = 0; // 0x0
- field public static final int IPCE_IPRM_REACHABILITY_LOST = 2; // 0x2
+ field public static final int IPCE_IPRM_NUD_FAILED = 2; // 0x2
+ field public static final int IPCE_IPRM_PROBE_FAILURE = 1; // 0x1
+ field public static final int IPCE_IPRM_PROBE_STARTED = 0; // 0x0
+ field public static final int IPCE_IPRM_PROVISIONING_LOST = 3; // 0x3
field public static final int IPCE_NETMON_BASE = 2048; // 0x800
+ field public static final int IPCE_NETMON_CAPPORT_FOUND = 2052; // 0x804
field public static final int IPCE_NETMON_CHECK_RESULT = 2049; // 0x801
+ field public static final int IPCE_NETMON_PORTAL_PROBE = 2051; // 0x803
field public static final int IPCE_NETMON_STATE_CHANGE = 2048; // 0x800
+ field public static final int IPCE_NETMON_VALIDATED = 2050; // 0x802
}
public final class IpManagerEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
@@ -26128,33 +26133,31 @@
field public final java.lang.String ifName;
}
- public final class IpReachabilityMonitorLostEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
+ public final class IpReachabilityEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
method public int describeContents();
- method public static void logEvent(java.lang.String);
+ method public static void logNudFailed(java.lang.String);
+ method public static void logProbeEvent(java.lang.String, int);
+ method public static void logProvisioningLost(java.lang.String);
method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.net.metrics.IpReachabilityMonitorLostEvent> CREATOR;
+ field public static final android.os.Parcelable.Creator<android.net.metrics.IpReachabilityEvent> CREATOR;
+ field public static final int NUD_FAILED = 512; // 0x200
+ field public static final int PROBE = 256; // 0x100
+ field public static final int PROVISIONING_LOST = 768; // 0x300
+ field public final int eventType;
field public final java.lang.String ifName;
}
- public final class IpReachabilityMonitorMessageEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
+ public final class NetworkMonitorEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
+ ctor public NetworkMonitorEvent(android.os.Parcel);
method public int describeContents();
- method public static void logEvent(java.lang.String, java.lang.String, int, int);
+ method public static void logCaptivePortalFound(int, long);
+ method public static void logPortalProbeEvent(int, long, int);
+ method public static void logValidated(int, long);
method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.net.metrics.IpReachabilityMonitorMessageEvent> CREATOR;
- field public final java.lang.String destination;
- field public final java.lang.String ifName;
- field public final int msgType;
- field public final int nudState;
- }
-
- public final class IpReachabilityMonitorProbeEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
- method public int describeContents();
- method public static void logEvent(java.lang.String, java.lang.String, boolean);
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.net.metrics.IpReachabilityMonitorProbeEvent> CREATOR;
- field public final java.lang.String destination;
- field public final java.lang.String ifName;
- field public final boolean success;
+ field public static final android.os.Parcelable.Creator<android.net.metrics.NetworkMonitorEvent> CREATOR;
+ field public final long durationMs;
+ field public final int netId;
+ field public final int returnCode;
}
}
@@ -31574,7 +31577,6 @@
field public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; // 0x1
field public static final deprecated int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
field public static final deprecated int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
- field public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 256; // 0x100
field public static final int USER_ACTIVITY_EVENT_ACCESSIBILITY = 3; // 0x3
field public static final int USER_ACTIVITY_EVENT_BUTTON = 1; // 0x1
field public static final int USER_ACTIVITY_EVENT_OTHER = 0; // 0x0
@@ -32830,7 +32832,7 @@
package android.printservice {
- public class CustomPrinterIconCallback {
+ public final class CustomPrinterIconCallback {
method public boolean onCustomPrinterIconLoaded(android.graphics.drawable.Icon);
}
@@ -46579,6 +46581,7 @@
method public void setSharedElementsUseOverlay(boolean);
method public void setSoftInputMode(int);
method public abstract void setStatusBarColor(int);
+ method public void setSustainedPerformanceMode(boolean);
method public abstract void setTitle(java.lang.CharSequence);
method public abstract deprecated void setTitleColor(int);
method public void setTransitionBackgroundFadeDuration(long);
@@ -61392,6 +61395,7 @@
method public java.lang.Object clone();
method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
+ method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
}
public class IllegalFormatCodePointException extends java.util.IllegalFormatException {
@@ -62374,6 +62378,8 @@
method public java.util.NavigableSet<K> navigableKeySet();
method public java.util.Map.Entry<K, V> pollFirstEntry();
method public java.util.Map.Entry<K, V> pollLastEntry();
+ method public boolean replace(K, V, V);
+ method public V replace(K, V);
method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
method public java.util.NavigableMap<K, V> subMap(K, boolean, K, boolean);
method public java.util.SortedMap<K, V> subMap(K, K);
diff --git a/api/test-current.txt b/api/test-current.txt
index 4020993..d5ecfd1 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -29214,7 +29214,6 @@
field public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; // 0x1
field public static final deprecated int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
field public static final deprecated int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
- field public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 256; // 0x100
}
public final class PowerManager.WakeLock {
@@ -30403,7 +30402,7 @@
package android.printservice {
- public class CustomPrinterIconCallback {
+ public final class CustomPrinterIconCallback {
method public boolean onCustomPrinterIconLoaded(android.graphics.drawable.Icon);
}
@@ -43707,6 +43706,7 @@
method public void setSharedElementsUseOverlay(boolean);
method public void setSoftInputMode(int);
method public abstract void setStatusBarColor(int);
+ method public void setSustainedPerformanceMode(boolean);
method public abstract void setTitle(java.lang.CharSequence);
method public abstract deprecated void setTitleColor(int);
method public void setTransitionBackgroundFadeDuration(long);
@@ -58164,6 +58164,7 @@
method public java.lang.Object clone();
method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
+ method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
}
public class IllegalFormatCodePointException extends java.util.IllegalFormatException {
@@ -59146,6 +59147,8 @@
method public java.util.NavigableSet<K> navigableKeySet();
method public java.util.Map.Entry<K, V> pollFirstEntry();
method public java.util.Map.Entry<K, V> pollLastEntry();
+ method public boolean replace(K, V, V);
+ method public V replace(K, V);
method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
method public java.util.NavigableMap<K, V> subMap(K, boolean, K, boolean);
method public java.util.SortedMap<K, V> subMap(K, K);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 424d355..2f7c550 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -126,6 +126,19 @@
public static final String META_HOME_ALTERNATE = "android.app.home.alternate";
/**
+ * Result for IActivityManager.startVoiceActivity: active session is currently hidden.
+ * @hide
+ */
+ public static final int START_VOICE_HIDDEN_SESSION = -10;
+
+ /**
+ * Result for IActivityManager.startVoiceActivity: active session does not match
+ * the requesting token.
+ * @hide
+ */
+ public static final int START_VOICE_NOT_ACTIVE_SESSION = -9;
+
+ /**
* Result for IActivityManager.startActivity: trying to start a background user
* activity that shouldn't be displayed for all users.
* @hide
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index ae2ca84..a3f3b2b3 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2959,6 +2959,13 @@
reply.writeNoException();
return true;
}
+ case START_CONFIRM_DEVICE_CREDENTIAL_INTENT: {
+ data.enforceInterface(IActivityManager.descriptor);
+ final Intent intent = Intent.CREATOR.createFromParcel(data);
+ startConfirmDeviceCredentialIntent(intent);
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -6931,5 +6938,16 @@
reply.recycle();
}
+ public void startConfirmDeviceCredentialIntent(Intent intent) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ intent.writeToParcel(data, 0);
+ mRemote.transact(START_CONFIRM_DEVICE_CREDENTIAL_INTENT, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index b28b5e6..66b4fcf 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -649,6 +649,8 @@
public void notifyLockedProfile(@UserIdInt int userId) throws RemoteException;
+ public void startConfirmDeviceCredentialIntent(Intent intent) throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -1032,4 +1034,5 @@
int IS_VR_PACKAGE_ENABLED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 371;
int SWAP_DOCKED_AND_FULLSCREEN_STACK = IBinder.FIRST_CALL_TRANSACTION + 372;
int NOTIFY_LOCKED_PROFILE = IBinder.FIRST_CALL_TRANSACTION + 373;
+ int START_CONFIRM_DEVICE_CREDENTIAL_INTENT = IBinder.FIRST_CALL_TRANSACTION + 374;
}
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index 2fc6533..a42aed6 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -43,7 +43,8 @@
* new wallpaper content is ready to display.
*/
ParcelFileDescriptor setWallpaper(String name, in String callingPackage,
- in Rect cropHint, out Bundle extras, int which, IWallpaperManagerCallback completion);
+ in Rect cropHint, boolean allowBackup, out Bundle extras, int which,
+ IWallpaperManagerCallback completion);
/**
* Set the live wallpaper. This only affects the system wallpaper.
@@ -125,6 +126,11 @@
boolean isWallpaperSettingAllowed(in String callingPackage);
/*
+ * Backup: is the current system wallpaper image eligible for off-device backup?
+ */
+ boolean isWallpaperBackupEligible(int userId);
+
+ /*
* Keyguard: register a callback for being notified that lock-state relevant
* wallpaper content has changed.
*/
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 4fca69a..95ea2a5 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1797,7 +1797,7 @@
if (res >= ActivityManager.START_SUCCESS) {
return;
}
-
+
switch (res) {
case ActivityManager.START_INTENT_NOT_RESOLVED:
case ActivityManager.START_CLASS_NOT_FOUND:
@@ -1820,6 +1820,15 @@
case ActivityManager.START_NOT_VOICE_COMPATIBLE:
throw new SecurityException(
"Starting under voice control not allowed for: " + intent);
+ case ActivityManager.START_VOICE_NOT_ACTIVE_SESSION:
+ throw new IllegalStateException(
+ "Session calling startVoiceActivity does not match active session");
+ case ActivityManager.START_VOICE_HIDDEN_SESSION:
+ throw new IllegalStateException(
+ "Cannot start voice activity on a hidden session");
+ case ActivityManager.START_CANCELED:
+ throw new AndroidRuntimeException("Activity could not be started for "
+ + intent);
default:
throw new AndroidRuntimeException("Unknown error code "
+ res + " when starting " + intent);
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index aef92cf..d8a3d4f 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -224,7 +224,7 @@
* @return a new AssetManager.
*/
@VisibleForTesting
- protected AssetManager createAssetManager(@NonNull final ResourcesKey key) {
+ protected @NonNull AssetManager createAssetManager(@NonNull final ResourcesKey key) {
AssetManager assets = new AssetManager();
// resDir can be null if the 'android' package is creating a new Resources object.
@@ -232,14 +232,15 @@
// already.
if (key.mResDir != null) {
if (assets.addAssetPath(key.mResDir) == 0) {
- return null;
+ throw new IllegalArgumentException("failed to add asset path " + key.mResDir);
}
}
if (key.mSplitResDirs != null) {
for (final String splitResDir : key.mSplitResDirs) {
if (assets.addAssetPath(splitResDir) == 0) {
- return null;
+ throw new IllegalArgumentException(
+ "failed to add split asset path " + splitResDir);
}
}
}
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 72b9318..18a5593 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -1,5 +1,5 @@
/*
-h * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2009 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.
@@ -875,7 +875,7 @@
/* Set the wallpaper to the default values */
ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(
"res:" + resources.getResourceName(resid),
- mContext.getOpPackageName(), null, result, which, completion);
+ mContext.getOpPackageName(), null, false, result, which, completion);
if (fd != null) {
FileOutputStream fos = null;
boolean ok = false;
@@ -985,7 +985,8 @@
final WallpaperSetCompletion completion = new WallpaperSetCompletion();
try {
ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
- mContext.getOpPackageName(), visibleCropHint, result, which, completion);
+ mContext.getOpPackageName(), visibleCropHint, allowBackup,
+ result, which, completion);
if (fd != null) {
FileOutputStream fos = null;
try {
@@ -1102,7 +1103,8 @@
final WallpaperSetCompletion completion = new WallpaperSetCompletion();
try {
ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
- mContext.getOpPackageName(), visibleCropHint, result, which, completion);
+ mContext.getOpPackageName(), visibleCropHint, allowBackup,
+ result, which, completion);
if (fd != null) {
FileOutputStream fos = null;
try {
@@ -1565,6 +1567,25 @@
}
}
+ /**
+ * Is the current system wallpaper eligible for backup?
+ *
+ * Only the OS itself may use this method.
+ * @hide
+ */
+ public boolean isWallpaperBackupEligible() {
+ if (sGlobals.mService == null) {
+ Log.w(TAG, "WallpaperService not running");
+ return false;
+ }
+ try {
+ return sGlobals.mService.isWallpaperBackupEligible(mContext.getUserId());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Exception querying wallpaper backup eligibility: " + e.getMessage());
+ }
+ return false;
+ }
+
// Private completion callback for setWallpaper() synchronization
private class WallpaperSetCompletion extends IWallpaperManagerCallback.Stub {
final CountDownLatch mLatch;
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index c84a0dc..602d950 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -24,7 +24,7 @@
import android.os.Parcelable;
import android.os.PersistableBundle;
import android.util.Log;
-import static android.util.TimeUtils.formatForLogging;
+import static android.util.TimeUtils.formatDuration;
import java.util.ArrayList;
@@ -760,15 +760,27 @@
" setRequiresDeviceIdle is an error.");
}
JobInfo job = new JobInfo(this);
- if (job.intervalMillis != job.getIntervalMillis()) {
- Log.w(TAG, "Specified interval for " + mJobService.getPackageName() + " is "
- + formatForLogging(mIntervalMillis) + ". Clamped to " +
- formatForLogging(job.getIntervalMillis()));
- }
- if (job.flexMillis != job.getFlexMillis()) {
- Log.w(TAG, "Specified interval for " + mJobService.getPackageName() + " is "
- + formatForLogging(mFlexMillis) + ". Clamped to " +
- formatForLogging(job.getFlexMillis()));
+ if (job.isPeriodic()) {
+ if (job.intervalMillis != job.getIntervalMillis()) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("Specified interval for ")
+ .append(String.valueOf(mJobId))
+ .append(" is ");
+ formatDuration(mIntervalMillis, builder);
+ builder.append(". Clamped to ");
+ formatDuration(job.getIntervalMillis(), builder);
+ Log.w(TAG, builder.toString());
+ }
+ if (job.flexMillis != job.getFlexMillis()) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("Specified flex for ")
+ .append(String.valueOf(mJobId))
+ .append(" is ");
+ formatDuration(mFlexMillis, builder);
+ builder.append(". Clamped to ");
+ formatDuration(job.getFlexMillis(), builder);
+ Log.w(TAG, builder.toString());
+ }
}
return job;
}
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index 5573896..6736d34 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -628,7 +628,12 @@
* close the camera further by unconfiguring and then firing {@code onClosed}.</p>
*/
private void finishPendingSequence(int sequenceId) {
- mSequenceDrainer.taskFinished(sequenceId);
+ try {
+ mSequenceDrainer.taskFinished(sequenceId);
+ } catch (IllegalStateException e) {
+ // Workaround for b/27870771
+ Log.w(TAG, e.getMessage());
+ }
}
private class SequenceDrainListener implements TaskDrainer.DrainListener {
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 271ec79..1ff2e8a 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -590,7 +590,7 @@
if (mService != null) try {
mRemovalCallback = callback;
mRemovalFingerprint = fp;
- mService.remove(mToken, fp.getFingerId(), userId, mServiceReceiver);
+ mService.remove(mToken, fp.getFingerId(), fp.getGroupId(), userId, mServiceReceiver);
} catch (RemoteException e) {
Log.w(TAG, "Remote exception in remove: ", e);
if (callback != null) {
@@ -810,11 +810,13 @@
if (mRemovalCallback != null) {
int reqFingerId = mRemovalFingerprint.getFingerId();
int reqGroupId = mRemovalFingerprint.getGroupId();
- if (reqFingerId != 0 && fingerId != reqFingerId) {
+ if (reqFingerId != 0 && fingerId != 0 && fingerId != reqFingerId) {
Log.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId);
+ return;
}
if (groupId != reqGroupId) {
Log.w(TAG, "Group id didn't match: " + groupId + " != " + reqGroupId);
+ return;
}
mRemovalCallback.onRemovalSucceeded(new Fingerprint(null, groupId, fingerId,
deviceId));
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index d7915e3..a83397a 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -41,7 +41,8 @@
void cancelEnrollment(IBinder token);
// Any errors resulting from this call will be returned to the listener
- void remove(IBinder token, int fingerId, int groupId, IFingerprintServiceReceiver receiver);
+ void remove(IBinder token, int fingerId, int groupId, int userId,
+ IFingerprintServiceReceiver receiver);
// Rename the fingerprint specified by fingerId and groupId to the given name
void rename(int fingerId, int groupId, String name);
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index f810fec..8a43acb 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -19,6 +19,7 @@
import com.android.internal.os.SomeArgs;
import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.content.Context;
@@ -644,14 +645,16 @@
*
* @param identifier The identifier for the input device.
* @param inputMethodInfo The input method.
- * @param inputMethodSubtype The input method subtype.
+ * @param inputMethodSubtype The input method subtype. {@code null} if this input method does
+ * not support any subtype.
*
* @return The associated {@link KeyboardLayout}, or null if one has not been set.
*
* @hide
*/
+ @Nullable
public KeyboardLayout getKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
- InputMethodInfo inputMethodInfo, InputMethodSubtype inputMethodSubtype) {
+ InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype inputMethodSubtype) {
try {
return mIm.getKeyboardLayoutForInputDevice(
identifier, inputMethodInfo, inputMethodSubtype);
@@ -666,13 +669,13 @@
* @param identifier The identifier for the input device.
* @param inputMethodInfo The input method with which to associate the keyboard layout.
* @param inputMethodSubtype The input method subtype which which to associate the keyboard
- * layout.
+ * layout. {@code null} if this input method does not support any subtype.
* @param keyboardLayoutDescriptor The descriptor of the keyboard layout to set
*
* @hide
*/
public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
- InputMethodInfo inputMethodInfo, InputMethodSubtype inputMethodSubtype,
+ InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype inputMethodSubtype,
String keyboardLayoutDescriptor) {
try {
mIm.setKeyboardLayoutForInputDevice(identifier, inputMethodInfo,
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index 89edaa9..0c3d4b3 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -43,6 +43,12 @@
private Handler mCallbackHandler;
/**
+ * @deprecated Use {@code mCallback} instead.
+ */
+ @Deprecated
+ private ICallback mLocalCallback;
+
+ /**
* An interface to receive asynchronous communication from the context hub.
*/
public abstract static class Callback {
@@ -64,6 +70,24 @@
}
/**
+ * @deprecated Use {@link Callback} instead.
+ * @hide
+ */
+ @Deprecated
+ public interface ICallback {
+ /**
+ * Callback function called on message receipt from context hub.
+ *
+ * @param hubHandle Handle (system-wide unique identifier) of the hub of the message.
+ * @param nanoAppHandle Handle (unique identifier) for app instance that sent the message.
+ * @param message The context hub message.
+ *
+ * @see ContextHubMessage
+ */
+ void onMessageReceipt(int hubHandle, int nanoAppHandle, ContextHubMessage message);
+ }
+
+ /**
* Get a handle to all the context hubs in the system
* @return array of context hub handles
*/
@@ -223,6 +247,20 @@
}
/**
+ * @deprecated Use {@link #registerCallback(Callback)} instead.
+ * @hide
+ */
+ @Deprecated
+ public int registerCallback(ICallback callback) {
+ if (mLocalCallback != null) {
+ Log.w(TAG, "Max number of local callbacks reached!");
+ return -1;
+ }
+ mLocalCallback = callback;
+ return 0;
+ }
+
+ /**
* Set a callback to receive messages from the context hub
*
* @param callback Callback object
@@ -266,6 +304,19 @@
return 0;
}
+ /**
+ * @deprecated Use {@link #unregisterCallback(Callback)} instead.
+ * @hide
+ */
+ public synchronized int unregisterCallback(ICallback callback) {
+ if (callback != mLocalCallback) {
+ Log.w(TAG, "Cannot recognize local callback!");
+ return -1;
+ }
+ mLocalCallback = null;
+ return 0;
+ }
+
private IContextHubCallback.Stub mClientCallback = new IContextHubCallback.Stub() {
@Override
public void onMessageReceipt(final int hubId, final int nanoAppId,
@@ -282,6 +333,12 @@
}
});
}
+ } else if (mLocalCallback != null) {
+ // we always ensure that mCallback takes precedence, because mLocalCallback is only
+ // for internal compatibility
+ synchronized (this) {
+ mLocalCallback.onMessageReceipt(hubId, nanoAppId, message);
+ }
} else {
Log.d(TAG, "Context hub manager client callback is NULL");
}
diff --git a/core/java/android/hardware/location/ContextHubService.java b/core/java/android/hardware/location/ContextHubService.java
index 2b9b974..8176189 100644
--- a/core/java/android/hardware/location/ContextHubService.java
+++ b/core/java/android/hardware/location/ContextHubService.java
@@ -19,6 +19,7 @@
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;
@@ -57,19 +58,17 @@
private static final int OS_APP_INSTANCE = -1;
private final Context mContext;
-
- private HashMap<Integer, NanoAppInstanceInfo> mNanoAppHash;
- private ContextHubInfo[] mContextHubInfo;
- private IContextHubCallback mCallback;
+ private final HashMap<Integer, NanoAppInstanceInfo> mNanoAppHash = new HashMap<>();
+ private final ContextHubInfo[] mContextHubInfo;
+ private final RemoteCallbackList<IContextHubCallback> mCallbacksList =
+ new RemoteCallbackList<>();
private native int nativeSendMessage(int[] header, byte[] data);
private native ContextHubInfo[] nativeInitialize();
-
public ContextHubService(Context context) {
mContext = context;
mContextHubInfo = nativeInitialize();
- mNanoAppHash = new HashMap<Integer, NanoAppInstanceInfo>();
for (int i = 0; i < mContextHubInfo.length; i++) {
Log.d(TAG, "ContextHub[" + i + "] id: " + mContextHubInfo[i].getId()
@@ -80,9 +79,7 @@
@Override
public int registerCallback(IContextHubCallback callback) throws RemoteException {
checkPermissions();
- synchronized (this) {
- mCallback = callback;
- }
+ mCallbacksList.register(callback);
return 0;
}
@@ -237,26 +234,26 @@
if (header == null || data == null || header.length < MSG_HEADER_SIZE) {
return -1;
}
-
- synchronized (this) {
- if (mCallback != null) {
- ContextHubMessage msg = new ContextHubMessage(header[MSG_FIELD_TYPE],
- header[MSG_FIELD_VERSION],
- data);
-
- try {
- mCallback.onMessageReceipt(header[MSG_FIELD_HUB_HANDLE],
- header[MSG_FIELD_APP_INSTANCE],
- msg);
- } catch (Exception e) {
- Log.w(TAG, "Exception " + e + " when calling remote callback");
- return -1;
- }
- } else {
- Log.d(TAG, "Message Callback is NULL");
+ int callbacksCount = mCallbacksList.beginBroadcast();
+ if (callbacksCount < 1) {
+ Log.v(TAG, "No message callbacks registered.");
+ return 0;
+ }
+ ContextHubMessage message =
+ new ContextHubMessage(header[MSG_FIELD_TYPE], header[MSG_FIELD_VERSION], data);
+ for (int i = 0; i < callbacksCount; ++i) {
+ IContextHubCallback callback = mCallbacksList.getBroadcastItem(i);
+ try {
+ callback.onMessageReceipt(
+ header[MSG_FIELD_HUB_HANDLE],
+ header[MSG_FIELD_APP_INSTANCE],
+ message);
+ } catch (RemoteException e) {
+ Log.i(TAG, "Exception (" + e + ") calling remote callback (" + callback + ").");
+ continue;
}
}
-
+ mCallbacksList.finishBroadcast();
return 0;
}
diff --git a/core/java/android/hardware/location/NanoAppInstanceInfo.java b/core/java/android/hardware/location/NanoAppInstanceInfo.java
index e842ec6..71a5a88 100644
--- a/core/java/android/hardware/location/NanoAppInstanceInfo.java
+++ b/core/java/android/hardware/location/NanoAppInstanceInfo.java
@@ -17,10 +17,14 @@
package android.hardware.location;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+import libcore.util.EmptyArray;
+
/**
* @hide
*/
@@ -43,6 +47,8 @@
private int mHandle;
public NanoAppInstanceInfo() {
+ mNeededSensors = EmptyArray.INT;
+ mOutputEvents = EmptyArray.INT;
}
/**
@@ -193,6 +199,7 @@
*
* @return int[] all the required sensors needed by this app
*/
+ @NonNull
public int[] getNeededSensors() {
return mNeededSensors;
}
@@ -204,8 +211,8 @@
*
* @hide
*/
- public void setNeededSensors(int[] neededSensors) {
- mNeededSensors = neededSensors;
+ public void setNeededSensors(@Nullable int[] neededSensors) {
+ mNeededSensors = neededSensors != null ? neededSensors : EmptyArray.INT;
}
/**
@@ -213,6 +220,7 @@
*
* @return all the events that can be generated by this app
*/
+ @NonNull
public int[] getOutputEvents() {
return mOutputEvents;
}
@@ -225,8 +233,8 @@
*
* @hide
*/
- public void setOutputEvents(int[] outputEvents) {
- mOutputEvents = outputEvents;
+ public void setOutputEvents(@Nullable int[] outputEvents) {
+ mOutputEvents = outputEvents != null ? outputEvents : EmptyArray.INT;
}
/**
@@ -280,12 +288,12 @@
mNeededWriteMemBytes = in.readInt();
mNeededExecMemBytes = in.readInt();
- int mNeededSensorsLength = in.readInt();
- mNeededSensors = new int[mNeededSensorsLength];
+ int neededSensorsLength = in.readInt();
+ mNeededSensors = new int[neededSensorsLength];
in.readIntArray(mNeededSensors);
- int mOutputEventsLength = in.readInt();
- mOutputEvents = new int[mOutputEventsLength];
+ int outputEventsLength = in.readInt();
+ mOutputEvents = new int[outputEventsLength];
in.readIntArray(mOutputEvents);
}
@@ -303,9 +311,9 @@
out.writeInt(mNeededWriteMemBytes);
out.writeInt(mNeededExecMemBytes);
+ // arrays are never null
out.writeInt(mNeededSensors.length);
out.writeIntArray(mNeededSensors);
-
out.writeInt(mOutputEvents.length);
out.writeIntArray(mOutputEvents);
}
diff --git a/core/java/android/net/metrics/CaptivePortalStateChangeEvent.java b/core/java/android/net/metrics/CaptivePortalStateChangeEvent.java
index aabd09b..a67589a 100644
--- a/core/java/android/net/metrics/CaptivePortalStateChangeEvent.java
+++ b/core/java/android/net/metrics/CaptivePortalStateChangeEvent.java
@@ -29,17 +29,21 @@
public static final int NETWORK_MONITOR_DISCONNECTED = 1;
public static final int NETWORK_MONITOR_VALIDATED = 2;
+ public final int netId;
public final int state;
- public CaptivePortalStateChangeEvent(int state) {
+ public CaptivePortalStateChangeEvent(int netId, int state) {
+ this.netId = netId;
this.state = state;
}
public CaptivePortalStateChangeEvent(Parcel in) {
+ netId = in.readInt();
state = in.readInt();
}
public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(netId);
out.writeInt(state);
}
@@ -58,7 +62,7 @@
}
};
- public static void logEvent(int state) {
- logEvent(IPCE_NETMON_STATE_CHANGE, new CaptivePortalStateChangeEvent(state));
+ public static void logEvent(int netId, int state) {
+ logEvent(IPCE_NETMON_STATE_CHANGE, new CaptivePortalStateChangeEvent(netId, state));
}
};
diff --git a/core/java/android/net/metrics/ConnectivityServiceChangeEvent.java b/core/java/android/net/metrics/DefaultNetworkEvent.java
similarity index 69%
rename from core/java/android/net/metrics/ConnectivityServiceChangeEvent.java
rename to core/java/android/net/metrics/DefaultNetworkEvent.java
index fce68bb..f3c357b 100644
--- a/core/java/android/net/metrics/ConnectivityServiceChangeEvent.java
+++ b/core/java/android/net/metrics/DefaultNetworkEvent.java
@@ -24,8 +24,7 @@
* {@hide}
*/
@SystemApi
-public final class ConnectivityServiceChangeEvent extends IpConnectivityEvent
- implements Parcelable {
+public final class DefaultNetworkEvent extends IpConnectivityEvent implements Parcelable {
// The ID of the network that has become the new default or NETID_UNSET if none.
public final int netId;
// The list of transport types of the new default network, for example TRANSPORT_WIFI, as
@@ -37,7 +36,7 @@
public final boolean prevIPv4;
public final boolean prevIPv6;
- private ConnectivityServiceChangeEvent(int netId, int[] transportTypes,
+ private DefaultNetworkEvent(int netId, int[] transportTypes,
int prevNetId, boolean prevIPv4, boolean prevIPv6) {
this.netId = netId;
this.transportTypes = transportTypes;
@@ -46,7 +45,7 @@
this.prevIPv6 = prevIPv6;
}
- private ConnectivityServiceChangeEvent(Parcel in) {
+ private DefaultNetworkEvent(Parcel in) {
this.netId = in.readInt();
this.transportTypes = in.createIntArray();
this.prevNetId = in.readInt();
@@ -66,21 +65,21 @@
return 0;
}
- public static final Parcelable.Creator<ConnectivityServiceChangeEvent> CREATOR
- = new Parcelable.Creator<ConnectivityServiceChangeEvent>() {
- public ConnectivityServiceChangeEvent createFromParcel(Parcel in) {
- return new ConnectivityServiceChangeEvent(in);
+ public static final Parcelable.Creator<DefaultNetworkEvent> CREATOR
+ = new Parcelable.Creator<DefaultNetworkEvent>() {
+ public DefaultNetworkEvent createFromParcel(Parcel in) {
+ return new DefaultNetworkEvent(in);
}
- public ConnectivityServiceChangeEvent[] newArray(int size) {
- return new ConnectivityServiceChangeEvent[size];
+ public DefaultNetworkEvent[] newArray(int size) {
+ return new DefaultNetworkEvent[size];
}
};
- public static void logEvent(int netId, int[] transportTypes,
- int prevNetId, boolean prevIPv4, boolean prevIPv6) {
- logEvent(IPCE_CONSRV_DEFAULT_NET_CHANGE,
- new ConnectivityServiceChangeEvent(
- netId, transportTypes, prevNetId, prevIPv4, prevIPv6));
+ public static void logEvent(
+ int netId, int[] transports, int prevNetId, boolean hadIPv4, boolean hadIPv6) {
+ final DefaultNetworkEvent ev =
+ new DefaultNetworkEvent(netId, transports, prevNetId, hadIPv4, hadIPv6);
+ logEvent(IPCE_CONSRV_DEFAULT_NET_CHANGE, ev);
}
};
diff --git a/core/java/android/net/metrics/IpConnectivityEvent.java b/core/java/android/net/metrics/IpConnectivityEvent.java
index 2eb8edb..0b5e354 100644
--- a/core/java/android/net/metrics/IpConnectivityEvent.java
+++ b/core/java/android/net/metrics/IpConnectivityEvent.java
@@ -39,9 +39,10 @@
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_IPRM_PROBE_STARTED = IPCE_IPRM_BASE + 0;
+ public static final int IPCE_IPRM_PROBE_FAILURE = IPCE_IPRM_BASE + 1;
+ public static final int IPCE_IPRM_NUD_FAILED = IPCE_IPRM_BASE + 2;
+ public static final int IPCE_IPRM_PROVISIONING_LOST = IPCE_IPRM_BASE + 3;
public static final int IPCE_DHCP_RECV_ERROR = IPCE_DHCP_BASE + 0;
public static final int IPCE_DHCP_PARSE_ERROR = IPCE_DHCP_BASE + 1;
@@ -49,6 +50,9 @@
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_NETMON_VALIDATED = IPCE_NETMON_BASE + 2;
+ public static final int IPCE_NETMON_PORTAL_PROBE = IPCE_NETMON_BASE + 3;
+ public static final int IPCE_NETMON_CAPPORT_FOUND = IPCE_NETMON_BASE + 4;
public static final int IPCE_CONSRV_DEFAULT_NET_CHANGE = IPCE_CONSRV_BASE + 0;
diff --git a/core/java/android/net/metrics/IpReachabilityEvent.java b/core/java/android/net/metrics/IpReachabilityEvent.java
new file mode 100644
index 0000000..73dcb94
--- /dev/null
+++ b/core/java/android/net/metrics/IpReachabilityEvent.java
@@ -0,0 +1,84 @@
+/*
+ * 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.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * {@hide}
+ */
+@SystemApi
+public final class IpReachabilityEvent extends IpConnectivityEvent implements Parcelable {
+
+ public static final int PROBE = 1 << 8;
+ public static final int NUD_FAILED = 2 << 8;
+ public static final int PROVISIONING_LOST = 3 << 8;
+
+ public final String ifName;
+ // eventType byte format (MSB to LSB):
+ // byte 0: unused
+ // byte 1: unused
+ // byte 2: type of event: PROBE, NUD_FAILED, PROVISIONING_LOST
+ // byte 3: kernel errno from RTNetlink or IpReachabilityMonitor
+ public final int eventType;
+
+ private IpReachabilityEvent(String ifName, int eventType) {
+ this.ifName = ifName;
+ this.eventType = eventType;
+ }
+
+ private IpReachabilityEvent(Parcel in) {
+ this.ifName = in.readString();
+ this.eventType = in.readInt();
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(ifName);
+ out.writeInt(eventType);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator<IpReachabilityEvent> CREATOR
+ = new Parcelable.Creator<IpReachabilityEvent>() {
+ public IpReachabilityEvent createFromParcel(Parcel in) {
+ return new IpReachabilityEvent(in);
+ }
+
+ public IpReachabilityEvent[] newArray(int size) {
+ return new IpReachabilityEvent[size];
+ }
+ };
+
+ public static void logProbeEvent(String ifName, int nlErrorCode) {
+ final int tag = (nlErrorCode == 0) ? IPCE_IPRM_PROBE_STARTED : IPCE_IPRM_PROBE_FAILURE;
+ final int eventType = PROBE | (nlErrorCode & 0xFF);
+ logEvent(tag, new IpReachabilityEvent(ifName, eventType));
+ }
+
+ public static void logNudFailed(String ifName) {
+ logEvent(IPCE_IPRM_NUD_FAILED, new IpReachabilityEvent(ifName, NUD_FAILED));
+ }
+
+ public static void logProvisioningLost(String ifName) {
+ logEvent(IPCE_IPRM_PROVISIONING_LOST, new IpReachabilityEvent(ifName, PROVISIONING_LOST));
+ }
+};
diff --git a/core/java/android/net/metrics/IpReachabilityMonitorLostEvent.java b/core/java/android/net/metrics/IpReachabilityMonitorLostEvent.java
deleted file mode 100644
index 5215995..0000000
--- a/core/java/android/net/metrics/IpReachabilityMonitorLostEvent.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * {@hide}
- */
-@SystemApi
-public final class IpReachabilityMonitorLostEvent extends IpConnectivityEvent
- implements Parcelable {
- public final String ifName;
-
- private IpReachabilityMonitorLostEvent(String ifName) {
- this.ifName = ifName;
- }
-
- private IpReachabilityMonitorLostEvent(Parcel in) {
- this.ifName = in.readString();
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(ifName);
- }
-
- public int describeContents() {
- return 0;
- }
-
- public static final Parcelable.Creator<IpReachabilityMonitorLostEvent> CREATOR
- = new Parcelable.Creator<IpReachabilityMonitorLostEvent>() {
- public IpReachabilityMonitorLostEvent createFromParcel(Parcel in) {
- return new IpReachabilityMonitorLostEvent(in);
- }
-
- public IpReachabilityMonitorLostEvent[] newArray(int size) {
- return new IpReachabilityMonitorLostEvent[size];
- }
- };
-
- public static void logEvent(String ifName) {
- logEvent(IPCE_IPRM_REACHABILITY_LOST, new IpReachabilityMonitorLostEvent(ifName));
- }
-};
diff --git a/core/java/android/net/metrics/IpReachabilityMonitorMessageEvent.java b/core/java/android/net/metrics/IpReachabilityMonitorMessageEvent.java
deleted file mode 100644
index 0ed8c1c..0000000
--- a/core/java/android/net/metrics/IpReachabilityMonitorMessageEvent.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * {@hide}
- */
-@SystemApi
-public final class IpReachabilityMonitorMessageEvent extends IpConnectivityEvent
- implements Parcelable {
- public final String ifName;
- public final String destination;
- public final int msgType;
- public final int nudState;
-
- private IpReachabilityMonitorMessageEvent(String ifName, String destination, int msgType,
- int nudState) {
- this.ifName = ifName;
- this.destination = destination;
- this.msgType = msgType;
- this.nudState = nudState;
- }
-
- private IpReachabilityMonitorMessageEvent(Parcel in) {
- this.ifName = in.readString();
- this.destination = in.readString();
- this.msgType = in.readInt();
- this.nudState = in.readInt();
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(ifName);
- out.writeString(destination);
- out.writeInt(msgType);
- out.writeInt(nudState);
- }
-
- public int describeContents() {
- return 0;
- }
-
- public static final Parcelable.Creator<IpReachabilityMonitorMessageEvent> CREATOR
- = new Parcelable.Creator<IpReachabilityMonitorMessageEvent>() {
- public IpReachabilityMonitorMessageEvent createFromParcel(Parcel in) {
- return new IpReachabilityMonitorMessageEvent(in);
- }
-
- public IpReachabilityMonitorMessageEvent[] newArray(int size) {
- return new IpReachabilityMonitorMessageEvent[size];
- }
- };
-
- public static void logEvent(String ifName, String destination, int msgType, int nudState) {
- logEvent(IPCE_IPRM_MESSAGE_RECEIVED,
- new IpReachabilityMonitorMessageEvent(ifName, destination, msgType, nudState));
- }
-};
diff --git a/core/java/android/net/metrics/IpReachabilityMonitorProbeEvent.java b/core/java/android/net/metrics/IpReachabilityMonitorProbeEvent.java
deleted file mode 100644
index a55c2b4..0000000
--- a/core/java/android/net/metrics/IpReachabilityMonitorProbeEvent.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * {@hide}
- */
-@SystemApi
-public final class IpReachabilityMonitorProbeEvent extends IpConnectivityEvent
- implements Parcelable {
- public final String ifName;
- public final String destination;
- public final boolean success;
-
- private IpReachabilityMonitorProbeEvent(String ifName, String destination, boolean success) {
- this.ifName = ifName;
- this.destination = destination;
- this.success = success;
- }
-
- private IpReachabilityMonitorProbeEvent(Parcel in) {
- this.ifName = in.readString();
- this.destination = in.readString();
- this.success = in.readByte() > 0 ? true : false;
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(ifName);
- out.writeString(destination);
- out.writeByte((byte)(success ? 1 : 0));
- }
-
- public int describeContents() {
- return 0;
- }
-
- public static final Parcelable.Creator<IpReachabilityMonitorProbeEvent> CREATOR
- = new Parcelable.Creator<IpReachabilityMonitorProbeEvent>() {
- public IpReachabilityMonitorProbeEvent createFromParcel(Parcel in) {
- return new IpReachabilityMonitorProbeEvent(in);
- }
-
- public IpReachabilityMonitorProbeEvent[] newArray(int size) {
- return new IpReachabilityMonitorProbeEvent[size];
- }
- };
-
- public static void logEvent(String ifName, String destination, boolean success) {
- logEvent(IPCE_IPRM_PROBE_RESULT,
- new IpReachabilityMonitorProbeEvent(ifName, destination, success));
- }
-};
diff --git a/core/java/android/net/metrics/NetworkMonitorEvent.java b/core/java/android/net/metrics/NetworkMonitorEvent.java
new file mode 100644
index 0000000..2371266
--- /dev/null
+++ b/core/java/android/net/metrics/NetworkMonitorEvent.java
@@ -0,0 +1,80 @@
+/*
+ * 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.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * {@hide}
+ */
+@SystemApi
+public final class NetworkMonitorEvent extends IpConnectivityEvent implements Parcelable {
+ public final int netId;
+ public final long durationMs;
+ public final int returnCode;
+
+ private NetworkMonitorEvent(int netId, long durationMs, int returnCode) {
+ this.netId = netId;
+ this.durationMs = durationMs;
+ this.returnCode = returnCode;
+ }
+
+ public NetworkMonitorEvent(Parcel in) {
+ netId = in.readInt();
+ durationMs = in.readLong();
+ returnCode = in.readInt();
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(netId);
+ out.writeLong(durationMs);
+ out.writeInt(returnCode);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator<NetworkMonitorEvent> CREATOR
+ = new Parcelable.Creator<NetworkMonitorEvent>() {
+ public NetworkMonitorEvent createFromParcel(Parcel in) {
+ return new NetworkMonitorEvent(in);
+ }
+
+ public NetworkMonitorEvent[] newArray(int size) {
+ return new NetworkMonitorEvent[size];
+ }
+ };
+
+ private static void logEvent(int eventType, int netId, long durationMs, int returnCode) {
+ logEvent(eventType, new NetworkMonitorEvent(netId, durationMs, returnCode));
+ }
+
+ public static void logValidated(int netId, long durationMs) {
+ logEvent(IPCE_NETMON_VALIDATED, netId, durationMs, 0);
+ }
+
+ public static void logPortalProbeEvent(int netId, long durationMs, int returnCode) {
+ logEvent(IPCE_NETMON_PORTAL_PROBE, netId, durationMs, returnCode);
+ }
+
+ public static void logCaptivePortalFound(int netId, long durationMs) {
+ logEvent(IPCE_NETMON_CAPPORT_FOUND, netId, durationMs, 0);
+ }
+};
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index 6d74056..004b2ce 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -65,11 +65,12 @@
sShouldDefuse = shouldDefuse;
}
+ // A parcel cannot be obtained during compile-time initialization. Put the
+ // empty parcel into an inner class that can be initialized separately. This
+ // allows to initialize BaseBundle, and classes depending on it.
/** {@hide} */
- static final Parcel EMPTY_PARCEL;
-
- static {
- EMPTY_PARCEL = Parcel.obtain();
+ static final class NoImagePreloadHolder {
+ public static final Parcel EMPTY_PARCEL = Parcel.obtain();
}
// Invariant - exactly one of mMap / mParcelledData will be null
@@ -156,8 +157,8 @@
*/
BaseBundle(BaseBundle b) {
if (b.mParcelledData != null) {
- if (b.mParcelledData == EMPTY_PARCEL) {
- mParcelledData = EMPTY_PARCEL;
+ if (b.isEmptyParcel()) {
+ mParcelledData = NoImagePreloadHolder.EMPTY_PARCEL;
} else {
mParcelledData = Parcel.obtain();
mParcelledData.appendFrom(b.mParcelledData, 0, b.mParcelledData.dataSize());
@@ -236,7 +237,7 @@
+ "clobber all data inside!", new Throwable());
}
- if (mParcelledData == EMPTY_PARCEL) {
+ if (isEmptyParcel()) {
if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
+ ": empty");
if (mMap == null) {
@@ -284,6 +285,13 @@
return mParcelledData != null;
}
+ /**
+ * @hide
+ */
+ public boolean isEmptyParcel() {
+ return mParcelledData == NoImagePreloadHolder.EMPTY_PARCEL;
+ }
+
/** @hide */
ArrayMap<String, Object> getMap() {
unparcel();
@@ -1368,7 +1376,7 @@
// Keep implementation in sync with writeToParcel() in
// frameworks/native/libs/binder/PersistableBundle.cpp.
if (mParcelledData != null) {
- if (mParcelledData == EMPTY_PARCEL) {
+ if (isEmptyParcel()) {
parcel.writeInt(0);
} else {
int length = mParcelledData.dataSize();
@@ -1416,7 +1424,7 @@
} else if (length == 0) {
// Empty Bundle or end of data.
- mParcelledData = EMPTY_PARCEL;
+ mParcelledData = NoImagePreloadHolder.EMPTY_PARCEL;
return;
}
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 1128074..ca64a96 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -38,12 +38,9 @@
public static final Bundle EMPTY;
- static final Parcel EMPTY_PARCEL;
-
static {
EMPTY = new Bundle();
EMPTY.mMap = ArrayMap.EMPTY;
- EMPTY_PARCEL = BaseBundle.EMPTY_PARCEL;
}
/**
@@ -1155,7 +1152,7 @@
@Override
public synchronized String toString() {
if (mParcelledData != null) {
- if (mParcelledData == EMPTY_PARCEL) {
+ if (isEmptyParcel()) {
return "Bundle[EMPTY_PARCEL]";
} else {
return "Bundle[mParcelledData.dataSize=" +
diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java
index b947c97..db9f4b1 100644
--- a/core/java/android/os/PersistableBundle.java
+++ b/core/java/android/os/PersistableBundle.java
@@ -38,12 +38,10 @@
XmlUtils.WriteMapCallback {
private static final String TAG_PERSISTABLEMAP = "pbundle_as_map";
public static final PersistableBundle EMPTY;
- static final Parcel EMPTY_PARCEL;
static {
EMPTY = new PersistableBundle();
EMPTY.mMap = ArrayMap.EMPTY;
- EMPTY_PARCEL = BaseBundle.EMPTY_PARCEL;
}
/** @hide */
@@ -278,7 +276,7 @@
@Override
synchronized public String toString() {
if (mParcelledData != null) {
- if (mParcelledData == EMPTY_PARCEL) {
+ if (isEmptyParcel()) {
return "PersistableBundle[EMPTY_PARCEL]";
} else {
return "PersistableBundle[mParcelledData.dataSize=" +
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 92edc62..c285acb 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -219,15 +219,6 @@
public static final int DRAW_WAKE_LOCK = 0x00000080;
/**
- * Wake lock level: Enables Sustained Performance Mode.
- * <p>
- * This is used by Gaming and VR applications to ensure the device
- * will provide consistent performance over a large amount of time.
- * </p>
- */
- public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 0x00000100;
-
- /**
* Mask for the wake lock level component of a combined wake lock level and flags integer.
*
* @hide
@@ -559,7 +550,6 @@
case PROXIMITY_SCREEN_OFF_WAKE_LOCK:
case DOZE_WAKE_LOCK:
case DRAW_WAKE_LOCK:
- case SUSTAINED_PERFORMANCE_WAKE_LOCK:
break;
default:
throw new IllegalArgumentException("Must specify a valid wake lock level.");
@@ -1033,7 +1023,7 @@
/**
* Returns True if the device supports Sustained Performance Mode.
* Applications Should check if the device supports this mode, before
- * using {@link #SUSTAINED_PERFORMANCE_WAKE_LOCK}.
+ * using {@link android.view.Window#setSustainedPerformanceMode}.
*/
public boolean isSustainedPerformanceModeSupported() {
return mContext.getResources().getBoolean(
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index 9801e1b..b3cf710 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -55,12 +55,16 @@
/**
- * Power hint: The user is interacting with the device. The corresponding data field must be
+ * Power hint:
+ * Interaction: The user is interacting with the device. The corresponding data field must be
* the expected duration of the fling, or 0 if unknown.
*
- * This must be kept in sync with the values in hardware/libhardware/include/hardware/power.h
+ * Sustained Performance Mode: Enable/Disables Sustained Performance Mode.
+ *
+ * These must be kept in sync with the values in hardware/libhardware/include/hardware/power.h
*/
public static final int POWER_HINT_INTERACTION = 2;
+ public static final int POWER_HINT_SUSTAINED_PERFORMANCE_MODE = 6;
public static String wakefulnessToString(int wakefulness) {
switch (wakefulness) {
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 71f0bd6..5d0ad55 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -778,6 +778,12 @@
public PrintDocumentAdapterDelegate(Activity activity,
PrintDocumentAdapter documentAdapter) {
+ if (activity.isFinishing()) {
+ // The activity is already dead hence the onActivityDestroyed callback won't be
+ // triggered. Hence it is not save to print in this situation.
+ throw new IllegalStateException("Cannot start printing for finishing activity");
+ }
+
mActivity = activity;
mDocumentAdapter = documentAdapter;
mHandler = new MyHandler(mActivity.getMainLooper());
diff --git a/core/java/android/printservice/CustomPrinterIconCallback.java b/core/java/android/printservice/CustomPrinterIconCallback.java
index 6b9d0d8..a1fbdab 100644
--- a/core/java/android/printservice/CustomPrinterIconCallback.java
+++ b/core/java/android/printservice/CustomPrinterIconCallback.java
@@ -27,7 +27,7 @@
/**
* Callback for {@link PrinterDiscoverySession#onRequestCustomPrinterIcon}.
*/
-public class CustomPrinterIconCallback {
+public final class CustomPrinterIconCallback {
/** The printer the call back is for */
private final @NonNull PrinterId mPrinterId;
private final @NonNull IPrintServiceClient mObserver;
diff --git a/core/java/android/printservice/PrintJob.java b/core/java/android/printservice/PrintJob.java
index 7a7ca23..3226f34 100644
--- a/core/java/android/printservice/PrintJob.java
+++ b/core/java/android/printservice/PrintJob.java
@@ -347,18 +347,15 @@
* <p />
* This overrides any previously set status set via {@link #setStatus(CharSequence)},
* {@link #setStatus(int)}, {@link #block(String)}, or {@link #fail(String)},
- * <p />
- * To clear the status use {@link #setStatus(CharSequence) <code>setStatus(null)</code>}
*
- * @param status The new status as a String resource.
+ * @param statusResId The new status as a String resource. If 0 the status will be empty.
*/
@MainThread
- public void setStatus(@StringRes int status) {
+ public void setStatus(@StringRes int statusResId) {
PrintService.throwIfNotCalledOnMainThread();
- Preconditions.checkArgument(status != 0, "status has to be != 0");
try {
- mPrintServiceClient.setStatusRes(mCachedInfo.getId(), status,
+ mPrintServiceClient.setStatusRes(mCachedInfo.getId(), statusResId,
mContext.getPackageName());
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error setting status for job: " + mCachedInfo.getId(), re);
diff --git a/core/java/android/printservice/PrinterDiscoverySession.java b/core/java/android/printservice/PrinterDiscoverySession.java
index 7b9533d..4987e8b 100644
--- a/core/java/android/printservice/PrinterDiscoverySession.java
+++ b/core/java/android/printservice/PrinterDiscoverySession.java
@@ -408,15 +408,15 @@
public abstract void onStartPrinterStateTracking(@NonNull PrinterId printerId);
/**
- * Request the custom icon for a printer. Once the icon is available use
- * {@link CustomPrinterIconCallback#onCustomPrinterIconLoaded} to send the data to the print
- * service.
+ * Called by the system to request the custom icon for a printer. Once the icon is available the
+ * print services uses {@link CustomPrinterIconCallback#onCustomPrinterIconLoaded} to send the
+ * icon to the system.
*
* @param printerId The printer to icon belongs to.
- * @param cancellationSignal Signal used to cancel the request
- * @param callback Callback for returning the icon to the print spooler.
+ * @param cancellationSignal Signal used to cancel the request.
+ * @param callback Callback for returning the icon to the system.
*
- * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon(boolean)
*/
public void onRequestCustomPrinterIcon(@NonNull PrinterId printerId,
@NonNull CancellationSignal cancellationSignal,
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 6b60f47..d80d4be 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6043,6 +6043,33 @@
public static final String ENABLED_VR_LISTENERS = "enabled_vr_listeners";
/**
+ * Behavior of the display while in VR mode.
+ *
+ * One of {@link #VR_DISPLAY_MODE_LOW_PERSISTENCE} or {@link #VR_DISPLAY_MODE_OFF}.
+ *
+ * @hide
+ */
+ public static final String VR_DISPLAY_MODE = "vr_display_mode";
+
+ /**
+ * Lower the display persistence while the system is in VR mode.
+ *
+ * @see PackageManager#FEATURE_VR_MODE_HIGH_PERFORMANCE
+ *
+ * @hide.
+ */
+ public static final int VR_DISPLAY_MODE_LOW_PERSISTENCE = 0;
+
+ /**
+ * Do not alter the display persistence while the system is in VR mode.
+ *
+ * @see PackageManager#FEATURE_VR_MODE_HIGH_PERFORMANCE
+ *
+ * @hide.
+ */
+ public static final int VR_DISPLAY_MODE_OFF = 1;
+
+ /**
* This are the settings to be backed up.
*
* NOTE: Settings are backed up and restored in the order they appear
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 97af8f4..1781d9d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -20619,6 +20619,12 @@
}
}
+ /**
+ * Updates the drag shadow for the ongoing drag and drop operation.
+ *
+ * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the
+ * new drag shadow.
+ */
public final void updateDragShadow(DragShadowBuilder shadowBuilder) {
if (ViewDebug.DEBUG_DRAG) {
Log.d(VIEW_LOG_TAG, "updateDragShadow");
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 2f3f0bf..72d63ea 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -43,6 +43,8 @@
import android.transition.TransitionManager;
import android.view.accessibility.AccessibilityEvent;
+import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+
import java.util.List;
/**
@@ -792,8 +794,9 @@
if (wp.packageName == null) {
wp.packageName = mContext.getPackageName();
}
- if (mHardwareAccelerated) {
- wp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+ if (mHardwareAccelerated ||
+ (mWindowAttributes.flags & FLAG_HARDWARE_ACCELERATED) != 0) {
+ wp.flags |= FLAG_HARDWARE_ACCELERATED;
}
}
@@ -1177,6 +1180,15 @@
return false;
}
+ /* Sets the Sustained Performance requirement for the calling window.
+ * @param enable disables or enables the mode.
+ */
+ public void setSustainedPerformanceMode(boolean enable) {
+ setPrivateFlags(enable
+ ? WindowManager.LayoutParams.PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE : 0,
+ WindowManager.LayoutParams.PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE);
+ }
+
private boolean isOutOfBounds(Context context, MotionEvent event) {
final int x = (int) event.getX();
final int y = (int) event.getY();
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 89e146b..54e9942 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1247,6 +1247,13 @@
public static final int PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND = 0x00020000;
/**
+ * Flag to indicate that this window needs Sustained Performance Mode if
+ * the device supports it.
+ * @hide
+ */
+ public static final int PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE = 0x00020000;
+
+ /**
* Control flags that are private to the platform.
* @hide
*/
diff --git a/core/java/com/android/internal/app/LocaleStore.java b/core/java/com/android/internal/app/LocaleStore.java
index 7803e52..e3fce51 100644
--- a/core/java/com/android/internal/app/LocaleStore.java
+++ b/core/java/com/android/internal/app/LocaleStore.java
@@ -126,12 +126,18 @@
return mFullCountryNameNative;
}
+ String getFullCountryNameInUiLanguage() {
+ // We don't cache the UI name because the default locale keeps changing
+ return LocaleHelper.getDisplayCountry(mLocale);
+ }
+
/** Returns the name of the locale in the language of the UI.
* It is used for search, but never shown.
* For instance German will show as "Deutsch" in the list, but we will also search for
* "allemand" if the system UI is in French.
*/
public String getFullNameInUiLanguage() {
+ // We don't cache the UI name because the default locale keeps changing
return LocaleHelper.getDisplayName(mLocale, true /* sentence case */);
}
@@ -154,6 +160,14 @@
}
}
+ String getContentDescription(boolean countryMode) {
+ if (countryMode) {
+ return getFullCountryNameInUiLanguage();
+ } else {
+ return getFullNameInUiLanguage();
+ }
+ }
+
public boolean getChecked() {
return mIsChecked;
}
diff --git a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
index e2d29e3..a4b5a8e 100644
--- a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
+++ b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
@@ -159,6 +159,7 @@
LocaleStore.LocaleInfo item = (LocaleStore.LocaleInfo) getItem(position);
text.setText(item.getLabel(mCountryMode));
text.setTextLocale(item.getLocale());
+ text.setContentDescription(item.getContentDescription(mCountryMode));
if (mCountryMode) {
int layoutDir = TextUtils.getLayoutDirectionFromLocale(item.getParent());
//noinspection ResourceType
diff --git a/core/java/com/android/internal/inputmethod/InputMethodSubtypeHandle.java b/core/java/com/android/internal/inputmethod/InputMethodSubtypeHandle.java
index 975021e8..04d7f9b 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodSubtypeHandle.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodSubtypeHandle.java
@@ -16,6 +16,7 @@
package com.android.internal.inputmethod;
+import android.annotation.Nullable;
import android.text.TextUtils;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodSubtype;
@@ -26,12 +27,12 @@
private final String mInputMethodId;
private final int mSubtypeId;
- public InputMethodSubtypeHandle(InputMethodInfo info, InputMethodSubtype subtype) {
+ public InputMethodSubtypeHandle(InputMethodInfo info, @Nullable InputMethodSubtype subtype) {
mInputMethodId = info.getId();
if (subtype != null) {
mSubtypeId = subtype.hashCode();
} else {
- mSubtypeId = 0;
+ mSubtypeId = InputMethodUtils.NOT_A_SUBTYPE_ID;
}
}
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index 1b52146..27ffb8b 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -94,14 +94,14 @@
private int mStatsType = BatteryStats.STATS_SINCE_CHARGED;
- long mRawRealtime;
- long mRawUptime;
- long mBatteryRealtime;
- long mBatteryUptime;
- long mTypeBatteryRealtime;
- long mTypeBatteryUptime;
- long mBatteryTimeRemaining;
- long mChargeTimeRemaining;
+ long mRawRealtimeUs;
+ long mRawUptimeUs;
+ long mBatteryRealtimeUs;
+ long mBatteryUptimeUs;
+ long mTypeBatteryRealtimeUs;
+ long mTypeBatteryUptimeUs;
+ long mBatteryTimeRemainingUs;
+ long mChargeTimeRemainingUs;
private long mStatsPeriod = 0;
@@ -389,22 +389,22 @@
mFlashlightPowerCalculator.reset();
mStatsType = statsType;
- mRawUptime = rawUptimeUs;
- mRawRealtime = rawRealtimeUs;
- mBatteryUptime = mStats.getBatteryUptime(rawUptimeUs);
- mBatteryRealtime = mStats.getBatteryRealtime(rawRealtimeUs);
- mTypeBatteryUptime = mStats.computeBatteryUptime(rawUptimeUs, mStatsType);
- mTypeBatteryRealtime = mStats.computeBatteryRealtime(rawRealtimeUs, mStatsType);
- mBatteryTimeRemaining = mStats.computeBatteryTimeRemaining(rawRealtimeUs);
- mChargeTimeRemaining = mStats.computeChargeTimeRemaining(rawRealtimeUs);
+ mRawUptimeUs = rawUptimeUs;
+ mRawRealtimeUs = rawRealtimeUs;
+ mBatteryUptimeUs = mStats.getBatteryUptime(rawUptimeUs);
+ mBatteryRealtimeUs = mStats.getBatteryRealtime(rawRealtimeUs);
+ mTypeBatteryUptimeUs = mStats.computeBatteryUptime(rawUptimeUs, mStatsType);
+ mTypeBatteryRealtimeUs = mStats.computeBatteryRealtime(rawRealtimeUs, mStatsType);
+ mBatteryTimeRemainingUs = mStats.computeBatteryTimeRemaining(rawRealtimeUs);
+ mChargeTimeRemainingUs = mStats.computeChargeTimeRemaining(rawRealtimeUs);
if (DEBUG) {
Log.d(TAG, "Raw time: realtime=" + (rawRealtimeUs/1000) + " uptime="
+ (rawUptimeUs/1000));
- Log.d(TAG, "Battery time: realtime=" + (mBatteryRealtime/1000) + " uptime="
- + (mBatteryUptime/1000));
- Log.d(TAG, "Battery type time: realtime=" + (mTypeBatteryRealtime/1000) + " uptime="
- + (mTypeBatteryUptime/1000));
+ Log.d(TAG, "Battery time: realtime=" + (mBatteryRealtimeUs /1000) + " uptime="
+ + (mBatteryUptimeUs /1000));
+ Log.d(TAG, "Battery type time: realtime=" + (mTypeBatteryRealtimeUs /1000) + " uptime="
+ + (mTypeBatteryUptimeUs /1000));
}
mMinDrainedPower = (mStats.getLowDischargeAmountSinceCharge()
* mPowerProfile.getBatteryCapacity()) / 100;
@@ -489,7 +489,7 @@
private void processAppUsage(SparseArray<UserHandle> asUsers) {
final boolean forAllUsers = (asUsers.get(UserHandle.USER_ALL) != null);
- mStatsPeriod = mTypeBatteryRealtime;
+ mStatsPeriod = mTypeBatteryRealtimeUs;
BatterySipper osSipper = null;
final SparseArray<? extends Uid> uidStats = mStats.getUidStats();
@@ -498,14 +498,14 @@
final Uid u = uidStats.valueAt(iu);
final BatterySipper app = new BatterySipper(BatterySipper.DrainType.APP, u, 0);
- mCpuPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
- mWakelockPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
- mMobileRadioPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
- mWifiPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
- mBluetoothPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
- mSensorPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
- mCameraPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
- mFlashlightPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
+ mCpuPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
+ mWakelockPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
+ mMobileRadioPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
+ mWifiPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
+ mBluetoothPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
+ mSensorPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
+ mCameraPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
+ mFlashlightPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
final double totalPower = app.sumPower();
if (DEBUG && totalPower != 0) {
@@ -547,14 +547,14 @@
// The device has probably been awake for longer than the screen on
// time and application wake lock time would account for. Assign
// this remainder to the OS, if possible.
- mWakelockPowerCalculator.calculateRemaining(osSipper, mStats, mRawRealtime,
- mRawUptime, mStatsType);
+ mWakelockPowerCalculator.calculateRemaining(osSipper, mStats, mRawRealtimeUs,
+ mRawUptimeUs, mStatsType);
osSipper.sumPower();
}
}
private void addPhoneUsage() {
- long phoneOnTimeMs = mStats.getPhoneOnTime(mRawRealtime, mStatsType) / 1000;
+ long phoneOnTimeMs = mStats.getPhoneOnTime(mRawRealtimeUs, mStatsType) / 1000;
double phoneOnPower = mPowerProfile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE)
* phoneOnTimeMs / (60*60*1000);
if (phoneOnPower != 0) {
@@ -562,16 +562,19 @@
}
}
+ /**
+ * Screen power is the additional power the screen takes while the device is running.
+ */
private void addScreenUsage() {
double power = 0;
- long screenOnTimeMs = mStats.getScreenOnTime(mRawRealtime, mStatsType) / 1000;
+ long screenOnTimeMs = mStats.getScreenOnTime(mRawRealtimeUs, mStatsType) / 1000;
power += screenOnTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_SCREEN_ON);
final double screenFullPower =
mPowerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL);
for (int i = 0; i < BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; i++) {
double screenBinPower = screenFullPower * (i + 0.5f)
/ BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS;
- long brightnessTime = mStats.getScreenBrightnessTime(i, mRawRealtime, mStatsType)
+ long brightnessTime = mStats.getScreenBrightnessTime(i, mRawRealtimeUs, mStatsType)
/ 1000;
double p = screenBinPower*brightnessTime;
if (DEBUG && p != 0) {
@@ -588,7 +591,7 @@
private void addRadioUsage() {
BatterySipper radio = new BatterySipper(BatterySipper.DrainType.CELL, null, 0);
- mMobileRadioPowerCalculator.calculateRemaining(radio, mStats, mRawRealtime, mRawUptime,
+ mMobileRadioPowerCalculator.calculateRemaining(radio, mStats, mRawRealtimeUs, mRawUptimeUs,
mStatsType);
radio.sumPower();
if (radio.totalPowerMah > 0) {
@@ -606,16 +609,26 @@
bs.sumPower();
}
+ /**
+ * Calculate the baseline power usage for the device when it is in suspend and idle.
+ * The device is drawing POWER_CPU_IDLE power at its lowest power state.
+ * The device is drawing POWER_CPU_IDLE + POWER_CPU_AWAKE power when a wakelock is held.
+ */
private void addIdleUsage() {
- long idleTimeMs = (mTypeBatteryRealtime
- - mStats.getScreenOnTime(mRawRealtime, mStatsType)) / 1000;
- double idlePower = (idleTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_IDLE))
- / (60*60*1000);
- if (DEBUG && idlePower != 0) {
- Log.d(TAG, "Idle: time=" + idleTimeMs + " power=" + makemAh(idlePower));
+ final double suspendPowerMaMs = (mTypeBatteryRealtimeUs / 1000) *
+ mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_IDLE);
+ final double idlePowerMaMs = (mTypeBatteryUptimeUs / 1000) *
+ mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_AWAKE);
+ final double totalPowerMah = (suspendPowerMaMs + idlePowerMaMs) / (60 * 60 * 1000);
+ if (DEBUG && totalPowerMah != 0) {
+ Log.d(TAG, "Suspend: time=" + (mTypeBatteryRealtimeUs / 1000)
+ + " power=" + makemAh(suspendPowerMaMs / (60 * 60 * 1000)));
+ Log.d(TAG, "Idle: time=" + (mTypeBatteryUptimeUs / 1000)
+ + " power=" + makemAh(idlePowerMaMs / (60 * 60 * 1000)));
}
- if (idlePower != 0) {
- addEntry(BatterySipper.DrainType.IDLE, idleTimeMs, idlePower);
+
+ if (totalPowerMah != 0) {
+ addEntry(BatterySipper.DrainType.IDLE, mTypeBatteryRealtimeUs / 1000, totalPowerMah);
}
}
@@ -628,7 +641,7 @@
*/
private void addWiFiUsage() {
BatterySipper bs = new BatterySipper(DrainType.WIFI, null, 0);
- mWifiPowerCalculator.calculateRemaining(bs, mStats, mRawRealtime, mRawUptime, mStatsType);
+ mWifiPowerCalculator.calculateRemaining(bs, mStats, mRawRealtimeUs, mRawUptimeUs, mStatsType);
aggregateSippers(bs, mWifiSippers, "WIFI");
if (bs.totalPowerMah > 0) {
mUsageList.add(bs);
@@ -641,7 +654,7 @@
*/
private void addBluetoothUsage() {
BatterySipper bs = new BatterySipper(BatterySipper.DrainType.BLUETOOTH, null, 0);
- mBluetoothPowerCalculator.calculateRemaining(bs, mStats, mRawRealtime, mRawUptime,
+ mBluetoothPowerCalculator.calculateRemaining(bs, mStats, mRawRealtimeUs, mRawUptimeUs,
mStatsType);
aggregateSippers(bs, mBluetoothSippers, "Bluetooth");
if (bs.totalPowerMah > 0) {
@@ -709,10 +722,6 @@
return mMaxDrainedPower;
}
- public long getBatteryTimeRemaining() { return mBatteryTimeRemaining; }
-
- public long getChargeTimeRemaining() { return mChargeTimeRemaining; }
-
public static byte[] readFully(FileInputStream stream) throws java.io.IOException {
return readFully(stream, stream.available());
}
diff --git a/core/java/com/android/internal/os/BinderInternal.java b/core/java/com/android/internal/os/BinderInternal.java
index d77b998..ea4575a 100644
--- a/core/java/com/android/internal/os/BinderInternal.java
+++ b/core/java/com/android/internal/os/BinderInternal.java
@@ -93,6 +93,8 @@
* @hide
*/
public static final native void disableBackgroundScheduling(boolean disable);
+
+ public static final native void setMaxThreads(int numThreads);
static native final void handleGc();
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 79138b7..d217474 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -51,7 +51,7 @@
* Power consumption when CPU is awake (when a wake lock is held). This
* should be 0 on devices that can go into full CPU power collapse even
* when a wake lock is held. Otherwise, this is the power consumption in
- * addition to POWERR_CPU_IDLE due to a wake lock being held but with no
+ * addition to POWER_CPU_IDLE due to a wake lock being held but with no
* CPU activity.
*/
public static final String POWER_CPU_AWAKE = "cpu.awake";
diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java
index 2d12fcd..9d296fa 100644
--- a/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -76,26 +76,6 @@
@Override
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) throws IOException {
- // We only back up the data under the current "wallpaper" schema with metadata
- IWallpaperManager wallpaper = (IWallpaperManager)ServiceManager.getService(
- Context.WALLPAPER_SERVICE);
- String[] files = new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO };
- String[] keys = new String[] { WALLPAPER_IMAGE_KEY, WALLPAPER_INFO_KEY };
- if (wallpaper != null) {
- try {
- final String wallpaperName = wallpaper.getName();
- if (wallpaperName != null && wallpaperName.length() > 0) {
- // When the wallpaper has a name, back up the info by itself.
- // TODO: Don't rely on the innards of the service object like this!
- // TODO: Send a delete for any stored wallpaper image in this case?
- files = new String[] { WALLPAPER_INFO };
- keys = new String[] { WALLPAPER_INFO_KEY };
- }
- } catch (RemoteException re) {
- Slog.e(TAG, "Couldn't get wallpaper name\n" + re);
- }
- }
- addHelper(WALLPAPER_HELPER, new WallpaperBackupHelper(this, files, keys));
addHelper(SYNC_SETTINGS_HELPER, new AccountSyncSettingsBackupHelper(this));
addHelper(PREFERRED_HELPER, new PreferredActivityBackupHelper());
addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(this));
@@ -107,30 +87,20 @@
@Override
public void onFullBackup(FullBackupDataOutput data) throws IOException {
- // At present we back up only the wallpaper
- fullWallpaperBackup(data);
- }
-
- private void fullWallpaperBackup(FullBackupDataOutput output) {
- // Back up the data files directly. We do them in this specific order --
- // info file followed by image -- because then we need take no special
- // steps during restore; the restore will happen properly when the individual
- // files are restored piecemeal.
- FullBackup.backupToTar(getPackageName(), FullBackup.ROOT_TREE_TOKEN, null,
- WALLPAPER_INFO_DIR, WALLPAPER_INFO, output);
- FullBackup.backupToTar(getPackageName(), FullBackup.ROOT_TREE_TOKEN, null,
- WALLPAPER_IMAGE_DIR, WALLPAPER_IMAGE, output);
+ // At present we don't back up anything
}
@Override
public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
throws IOException {
+ // Slot in a restore helper for the older wallpaper backup schema to support restore
+ // from devices still generating data in that format.
mWallpaperHelper = new WallpaperBackupHelper(this,
new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO },
new String[] { WALLPAPER_IMAGE_KEY, WALLPAPER_INFO_KEY} );
addHelper(WALLPAPER_HELPER, mWallpaperHelper);
- // On restore, we also support a previous data schema "system_files"
+ // On restore, we also support a long-ago wallpaper data schema "system_files"
addHelper("system_files", new WallpaperBackupHelper(this,
new String[] { WALLPAPER_IMAGE },
new String[] { WALLPAPER_IMAGE_KEY} ));
@@ -213,6 +183,9 @@
@Override
public void onRestoreFinished() {
- mWallpaperHelper.onRestoreFinished();
+ // helper will be null following 'adb restore' or other full-data operation
+ if (mWallpaperHelper != null) {
+ mWallpaperHelper.onRestoreFinished();
+ }
}
}
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index abc6c4b..5559d48 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -917,6 +917,12 @@
IPCThreadState::disableBackgroundScheduling(disable ? true : false);
}
+static void android_os_BinderInternal_setMaxThreads(JNIEnv* env,
+ jobject clazz, jint maxThreads)
+{
+ ProcessState::self()->setThreadPoolMaxThreadCount(maxThreads);
+}
+
static void android_os_BinderInternal_handleGc(JNIEnv* env, jobject clazz)
{
ALOGV("Gc has executed, clearing binder ops");
@@ -930,6 +936,7 @@
{ "getContextObject", "()Landroid/os/IBinder;", (void*)android_os_BinderInternal_getContextObject },
{ "joinThreadPool", "()V", (void*)android_os_BinderInternal_joinThreadPool },
{ "disableBackgroundScheduling", "(Z)V", (void*)android_os_BinderInternal_disableBackgroundScheduling },
+ { "setMaxThreads", "(I)V", (void*)android_os_BinderInternal_setMaxThreads },
{ "handleGc", "()V", (void*)android_os_BinderInternal_handleGc }
};
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 6776d3b..2040d7d 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -497,14 +497,14 @@
<string name="bugreport_option_interactive_title">Interactive report</string>
<!-- Summary in the bugreport dialog for the interactive workflow. [CHAR LIMIT=NONE] -->
<string name="bugreport_option_interactive_summary">Use this under most circumstances.
- It allows you to track progress of the report and enter more details about the problem.
+ It allows you to track progress of the report, enter more details about the problem, and take screenshots.
It might omit some less-used sections that take a long time to report.</string>
<!-- Title in the bugreport dialog for the full workflow. Should fit in one line. [CHAR LIMIT=30] -->
<string name="bugreport_option_full_title">Full report</string>
<!-- Summary in the bugreport dialog for the full workflow. [CHAR LIMIT=NONE] -->
<string name="bugreport_option_full_summary">Use this option for minimal system interference when
your device is unresponsive or too slow, or when you need all report sections.
- Does not take a screenshot or allow you to enter more details.</string>
+ Does not allow you to enter more details or take additional screenshots.</string>
<!-- Toast message informing user in how many seconds a bugreport screenshot will be taken -->
<plurals name="bugreport_countdown">
<item quantity="one">Taking screenshot for bug report in <xliff:g id="number">%d</xliff:g> second.</item>
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 15cb684..c3dfb89 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -562,7 +562,7 @@
if ((mHeader->flags&ResStringPool_header::UTF8_FLAG &&
((uint8_t*)mStrings)[mStringPoolSize-1] != 0) ||
- (!mHeader->flags&ResStringPool_header::UTF8_FLAG &&
+ (!(mHeader->flags&ResStringPool_header::UTF8_FLAG) &&
((uint16_t*)mStrings)[mStringPoolSize-1] != 0)) {
ALOGW("Bad string block: last string is not 0-terminated\n");
return (mError=BAD_TYPE);
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 6259466..8857c41 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -247,6 +247,7 @@
tests/unit/DamageAccumulatorTests.cpp \
tests/unit/DeviceInfoTests.cpp \
tests/unit/FatVectorTests.cpp \
+ tests/unit/FontRendererTests.cpp \
tests/unit/GlopBuilderTests.cpp \
tests/unit/GpuMemoryTrackerTests.cpp \
tests/unit/GradientCacheTests.cpp \
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 1b618c6..276c18d 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -689,7 +689,7 @@
void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) {
uint32_t intRadius = Blur::convertRadiusToInt(radius);
#ifdef ANDROID_ENABLE_RENDERSCRIPT
- if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF) {
+ if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF && radius <= 25.0f) {
uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
if (mRs == nullptr) {
diff --git a/libs/hwui/tests/unit/FontRendererTests.cpp b/libs/hwui/tests/unit/FontRendererTests.cpp
new file mode 100644
index 0000000..99080ac
--- /dev/null
+++ b/libs/hwui/tests/unit/FontRendererTests.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include "GammaFontRenderer.h"
+#include "tests/common/TestUtils.h"
+
+using namespace android::uirenderer;
+
+static bool isZero(uint8_t* data, int size) {
+ for (int i = 0; i < size; i++) {
+ if (data[i]) return false;
+ }
+ return true;
+}
+
+RENDERTHREAD_TEST(FontRenderer, renderDropShadow) {
+ SkPaint paint;
+ paint.setTextSize(10);
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ GammaFontRenderer gammaFontRenderer;
+ FontRenderer& fontRenderer = gammaFontRenderer.getFontRenderer();
+ fontRenderer.setFont(&paint, SkMatrix::I());
+
+ std::vector<glyph_t> glyphs;
+ std::vector<float> positions;
+ float totalAdvance;
+ Rect bounds;
+ TestUtils::layoutTextUnscaled(paint, "This is a test",
+ &glyphs, &positions, &totalAdvance, &bounds);
+
+ for (int radius : {28, 20, 2}) {
+ auto result = fontRenderer.renderDropShadow(&paint, glyphs.data(), glyphs.size(),
+ radius, positions.data());
+ ASSERT_NE(nullptr, result.image);
+ EXPECT_FALSE(isZero(result.image, result.width * result.height));
+ EXPECT_LE(bounds.getWidth() + radius * 2, (int) result.width);
+ EXPECT_LE(bounds.getHeight() + radius * 2, (int) result.height);
+ delete result.image;
+ }
+}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 00eff91..23ae691 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1502,11 +1502,16 @@
*/
public boolean isBluetoothA2dpOn() {
if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP,"")
- == AudioSystem.DEVICE_STATE_UNAVAILABLE) {
- return false;
- } else {
+ == AudioSystem.DEVICE_STATE_AVAILABLE) {
+ return true;
+ } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,"")
+ == AudioSystem.DEVICE_STATE_AVAILABLE) {
+ return true;
+ } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER,"")
+ == AudioSystem.DEVICE_STATE_AVAILABLE) {
return true;
}
+ return false;
}
/**
diff --git a/media/java/android/media/midi/MidiDevice.java b/media/java/android/media/midi/MidiDevice.java
index e4588fe..da44ca6 100644
--- a/media/java/android/media/midi/MidiDevice.java
+++ b/media/java/android/media/midi/MidiDevice.java
@@ -42,6 +42,7 @@
private final IMidiManager mMidiManager;
private final IBinder mClientToken;
private final IBinder mDeviceToken;
+ private boolean mIsDeviceClosed;
private final CloseGuard mGuard = CloseGuard.get();
@@ -123,6 +124,9 @@
* or null in case of failure.
*/
public MidiInputPort openInputPort(int portNumber) {
+ if (mIsDeviceClosed) {
+ return null;
+ }
try {
IBinder token = new Binder();
ParcelFileDescriptor pfd = mDeviceServer.openInputPort(token, portNumber);
@@ -146,6 +150,9 @@
* or null in case of failure.
*/
public MidiOutputPort openOutputPort(int portNumber) {
+ if (mIsDeviceClosed) {
+ return null;
+ }
try {
IBinder token = new Binder();
ParcelFileDescriptor pfd = mDeviceServer.openOutputPort(token, portNumber);
@@ -175,12 +182,15 @@
if (outputPortNumber < 0 || outputPortNumber >= mDeviceInfo.getOutputPortCount()) {
throw new IllegalArgumentException("outputPortNumber out of range");
}
+ if (mIsDeviceClosed) {
+ return null;
+ }
ParcelFileDescriptor pfd = inputPort.claimFileDescriptor();
if (pfd == null) {
return null;
}
- try {
+ try {
IBinder token = new Binder();
int calleePid = mDeviceServer.connectPorts(token, pfd, outputPortNumber);
// If the service is a different Process then it will duplicate the pfd
@@ -202,11 +212,14 @@
@Override
public void close() throws IOException {
synchronized (mGuard) {
- mGuard.close();
- try {
- mMidiManager.closeDevice(mClientToken, mDeviceToken);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException in closeDevice");
+ if (!mIsDeviceClosed) {
+ mGuard.close();
+ mIsDeviceClosed = true;
+ try {
+ mMidiManager.closeDevice(mClientToken, mDeviceToken);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in closeDevice");
+ }
}
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
index ecdbe63..32fdb64 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
@@ -70,11 +70,7 @@
}
public boolean isDocumentEnabled(String docMimeType, int docFlags) {
- if (isDirectory(docMimeType)) {
- return true;
- }
-
- return MimePredicate.mimeMatches(mState.acceptMimes, docMimeType);
+ return true;
}
abstract void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch);
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index 8c2af45..9aaddaa 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -1213,44 +1213,55 @@
}
}
+ /**
+ * Compare by label, then package name, then uid.
+ */
public static final Comparator<AppEntry> ALPHA_COMPARATOR = new Comparator<AppEntry>() {
private final Collator sCollator = Collator.getInstance();
@Override
public int compare(AppEntry object1, AppEntry object2) {
- return sCollator.compare(object1.label, object2.label);
+ int compareResult = sCollator.compare(object1.label, object2.label);
+ if (compareResult != 0) {
+ return compareResult;
+ }
+ if (object1.info != null && object2.info != null) {
+ compareResult =
+ sCollator.compare(object1.info.packageName, object2.info.packageName);
+ if (compareResult != 0) {
+ return compareResult;
+ }
+ }
+ return object1.info.uid - object2.info.uid;
}
};
public static final Comparator<AppEntry> SIZE_COMPARATOR
= new Comparator<AppEntry>() {
- private final Collator sCollator = Collator.getInstance();
@Override
public int compare(AppEntry object1, AppEntry object2) {
if (object1.size < object2.size) return 1;
if (object1.size > object2.size) return -1;
- return sCollator.compare(object1.label, object2.label);
+ return ALPHA_COMPARATOR.compare(object1, object2);
}
};
public static final Comparator<AppEntry> INTERNAL_SIZE_COMPARATOR
= new Comparator<AppEntry>() {
- private final Collator sCollator = Collator.getInstance();
@Override
public int compare(AppEntry object1, AppEntry object2) {
if (object1.internalSize < object2.internalSize) return 1;
if (object1.internalSize > object2.internalSize) return -1;
- return sCollator.compare(object1.label, object2.label);
+ return ALPHA_COMPARATOR.compare(object1, object2);
}
};
public static final Comparator<AppEntry> EXTERNAL_SIZE_COMPARATOR
= new Comparator<AppEntry>() {
- private final Collator sCollator = Collator.getInstance();
@Override
public int compare(AppEntry object1, AppEntry object2) {
if (object1.externalSize < object2.externalSize) return 1;
if (object1.externalSize > object2.externalSize) return -1;
- return sCollator.compare(object1.label, object2.label);
+ return ALPHA_COMPARATOR.compare(object1, object2);
}
};
@@ -1272,21 +1283,18 @@
}
};
- public static final AppFilter FILTER_PERSONAL_WITHOUT_DISABLED_UNTIL_USED = new AppFilter() {
- private int mCurrentUser;
-
+ public static final AppFilter FILTER_WITHOUT_DISABLED_UNTIL_USED = new AppFilter() {
public void init() {
- mCurrentUser = ActivityManager.getCurrentUser();
+ // do nothings
}
@Override
public boolean filterApp(AppEntry entry) {
- return UserHandle.getUserId(entry.info.uid) == mCurrentUser &&
- entry.info.enabledSetting != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
+ return entry.info.enabledSetting
+ != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
}
};
-
public static final AppFilter FILTER_WORK = new AppFilter() {
private int mCurrentUser;
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 2b1c66d..7d279eb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -504,20 +504,7 @@
}
private void updateWifiState(int state) {
- if (state == WifiManager.WIFI_STATE_ENABLED) {
- if (mScanner != null) {
- // We only need to resume if mScanner isn't null because
- // that means we want to be scanning.
- mScanner.resume();
- }
- } else {
- mLastInfo = null;
- mLastNetworkInfo = null;
- if (mScanner != null) {
- mScanner.pause();
- }
- }
- mMainHandler.obtainMessage(MainHandler.MSG_WIFI_STATE_CHANGED, state, 0).sendToTarget();
+ mWorkHandler.obtainMessage(WorkHandler.MSG_UPDATE_WIFI_STATE, state, 0).sendToTarget();
}
public static List<AccessPoint> getCurrentAccessPoints(Context context, boolean includeSaved,
@@ -609,6 +596,7 @@
private static final int MSG_UPDATE_ACCESS_POINTS = 0;
private static final int MSG_UPDATE_NETWORK_INFO = 1;
private static final int MSG_RESUME = 2;
+ private static final int MSG_UPDATE_WIFI_STATE = 3;
public WorkHandler(Looper looper) {
super(looper);
@@ -626,6 +614,23 @@
case MSG_RESUME:
handleResume();
break;
+ case MSG_UPDATE_WIFI_STATE:
+ if (msg.arg1 == WifiManager.WIFI_STATE_ENABLED) {
+ if (mScanner != null) {
+ // We only need to resume if mScanner isn't null because
+ // that means we want to be scanning.
+ mScanner.resume();
+ }
+ } else {
+ mLastInfo = null;
+ mLastNetworkInfo = null;
+ if (mScanner != null) {
+ mScanner.pause();
+ }
+ }
+ mMainHandler.obtainMessage(MainHandler.MSG_WIFI_STATE_CHANGED, msg.arg1, 0)
+ .sendToTarget();
+ break;
}
}
}
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index ec39998..7023a1a 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -198,6 +198,11 @@
private File mScreenshotsDir;
/**
+ * id of the notification used to set service on foreground.
+ */
+ private int mForegroundId = -1;
+
+ /**
* Flag indicating whether a screenshot is being taken.
* <p>
* This is the only state that is shared between the 2 handlers and hence must have synchronized
@@ -257,6 +262,7 @@
writer.printf("No monitored processes");
return;
}
+ writer.printf("Foreground id: %d\n\n", mForegroundId);
writer.printf("Monitored dumpstate processes\n");
writer.printf("-----------------------------\n");
for (int i = 0; i < size; i++) {
@@ -479,10 +485,21 @@
return;
}
if (DEBUG) {
- Log.d(TAG, "Sending 'Progress' notification for id " + info.id + "(pid " + info.pid
+ Log.d(TAG, "Sending 'Progress' notification for id " + info.id + " (pid " + info.pid
+ "): " + percentageText);
}
- NotificationManager.from(mContext).notify(TAG, info.id, notification);
+ sendForegroundabledNotification(info.id, notification);
+ }
+
+ private void sendForegroundabledNotification(int id, Notification notification) {
+ if (mForegroundId >= 0) {
+ if (DEBUG) Log.d(TAG, "Already running as foreground service");
+ NotificationManager.from(mContext).notify(id, notification);
+ } else {
+ mForegroundId = id;
+ Log.d(TAG, "Start running as foreground service on id " + mForegroundId);
+ startForeground(mForegroundId, notification);
+ }
}
/**
@@ -506,8 +523,10 @@
Log.d(TAG, "Removing ID " + id);
mProcesses.remove(id);
}
- Log.v(TAG, "stopProgress(" + id + "): cancel notification");
- NotificationManager.from(mContext).cancel(TAG, id);
+ // Must stop foreground service first, otherwise notif.cancel() will fail below.
+ stopForegroundWhenDone(id);
+ Log.d(TAG, "stopProgress(" + id + "): cancel notification");
+ NotificationManager.from(mContext).cancel(id);
stopSelfWhenDone();
}
@@ -625,7 +644,7 @@
Log.w(TAG, "launchBugreportInfoDialog(): canceling notification because id " + id
+ " was not found");
// TODO: add test case to make sure notification is canceled.
- NotificationManager.from(mContext).cancel(TAG, id);
+ NotificationManager.from(mContext).cancel(id);
return;
}
@@ -648,7 +667,7 @@
Log.w(TAG, "takeScreenshot(): canceling notification because id " + id
+ " was not found");
// TODO: add test case to make sure notification is canceled.
- NotificationManager.from(mContext).cancel(TAG, id);
+ NotificationManager.from(mContext).cancel(id);
return;
}
setTakingScreenshot(true);
@@ -731,7 +750,7 @@
if (info.finished) {
Log.d(TAG, "Screenshot finished after bugreport; updating share notification");
info.renameScreenshots(mScreenshotsDir);
- sendBugreportNotification(mContext, info, mTakingScreenshot);
+ sendBugreportNotification(info, mTakingScreenshot);
}
msg = mContext.getString(R.string.bugreport_screenshot_taken);
} else {
@@ -753,6 +772,33 @@
}
/**
+ * Stop running on foreground once there is no more active bugreports being watched.
+ */
+ private void stopForegroundWhenDone(int id) {
+ if (id != mForegroundId) {
+ Log.d(TAG, "stopForegroundWhenDone(" + id + "): ignoring since foreground id is "
+ + mForegroundId);
+ return;
+ }
+
+ Log.d(TAG, "detaching foreground from id " + mForegroundId);
+ stopForeground(Service.STOP_FOREGROUND_DETACH);
+ mForegroundId = -1;
+
+ // Might need to restart foreground using a new notification id.
+ final int total = mProcesses.size();
+ if (total > 0) {
+ for (int i = 0; i < total; i++) {
+ final BugreportInfo info = mProcesses.valueAt(i);
+ if (!info.finished) {
+ updateProgress(info);
+ break;
+ }
+ }
+ }
+ }
+
+ /**
* Finishes the service when it's not monitoring any more processes.
*/
private void stopSelfWhenDone() {
@@ -797,6 +843,9 @@
}
info.finished = true;
+ // Stop running on foreground, otherwise share notification cannot be dismissed.
+ stopForegroundWhenDone(id);
+
final Configuration conf = mContext.getResources().getConfiguration();
if ((conf.uiMode & Configuration.UI_MODE_TYPE_MASK) != Configuration.UI_MODE_TYPE_WATCH) {
triggerLocalNotification(mContext, info);
@@ -820,10 +869,10 @@
boolean isPlainText = info.bugreportFile.getName().toLowerCase().endsWith(".txt");
if (!isPlainText) {
// Already zipped, send it right away.
- sendBugreportNotification(context, info, mTakingScreenshot);
+ sendBugreportNotification(info, mTakingScreenshot);
} else {
// Asynchronously zip the file first, then send it.
- sendZippedBugreportNotification(context, info, mTakingScreenshot);
+ sendZippedBugreportNotification(info, mTakingScreenshot);
}
}
@@ -905,7 +954,7 @@
Log.v(TAG, "shareBugReport(): id " + id + " info = " + info);
}
- addDetailsToZipFile(mContext, info);
+ addDetailsToZipFile(info);
final Intent sendIntent = buildSendIntent(mContext, info);
if (sendIntent == null) {
@@ -934,36 +983,35 @@
/**
* Sends a notification indicating the bugreport has finished so use can share it.
*/
- private static void sendBugreportNotification(Context context, BugreportInfo info,
- boolean takingScreenshot) {
+ private void sendBugreportNotification(BugreportInfo info, boolean takingScreenshot) {
// Since adding the details can take a while, do it before notifying user.
- addDetailsToZipFile(context, info);
+ addDetailsToZipFile(info);
final Intent shareIntent = new Intent(INTENT_BUGREPORT_SHARE);
- shareIntent.setClass(context, BugreportProgressService.class);
+ shareIntent.setClass(mContext, BugreportProgressService.class);
shareIntent.setAction(INTENT_BUGREPORT_SHARE);
shareIntent.putExtra(EXTRA_ID, info.id);
shareIntent.putExtra(EXTRA_INFO, info);
- final String title = context.getString(R.string.bugreport_finished_title, info.id);
+ final String title = mContext.getString(R.string.bugreport_finished_title, info.id);
final String content = takingScreenshot ?
- context.getString(R.string.bugreport_finished_pending_screenshot_text)
- : context.getString(R.string.bugreport_finished_text);
- final Notification.Builder builder = newBaseNotification(context)
+ mContext.getString(R.string.bugreport_finished_pending_screenshot_text)
+ : mContext.getString(R.string.bugreport_finished_text);
+ final Notification.Builder builder = newBaseNotification(mContext)
.setContentTitle(title)
.setTicker(title)
.setContentText(content)
- .setContentIntent(PendingIntent.getService(context, info.id, shareIntent,
+ .setContentIntent(PendingIntent.getService(mContext, info.id, shareIntent,
PendingIntent.FLAG_UPDATE_CURRENT))
- .setDeleteIntent(newCancelIntent(context, info));
+ .setDeleteIntent(newCancelIntent(mContext, info));
if (!TextUtils.isEmpty(info.name)) {
builder.setSubText(info.name);
}
Log.v(TAG, "Sending 'Share' notification for ID " + info.id + ": " + title);
- NotificationManager.from(context).notify(TAG, info.id, builder.build());
+ NotificationManager.from(mContext).notify(info.id, builder.build());
}
/**
@@ -971,14 +1019,14 @@
* finishes - at this point there is nothing to be done other than waiting, hence it has no
* pending action.
*/
- private static void sendBugreportBeingUpdatedNotification(Context context, int id) {
+ private void sendBugreportBeingUpdatedNotification(Context context, int id) {
final String title = context.getString(R.string.bugreport_updating_title);
final Notification.Builder builder = newBaseNotification(context)
.setContentTitle(title)
.setTicker(title)
.setContentText(context.getString(R.string.bugreport_updating_wait));
Log.v(TAG, "Sending 'Updating zip' notification for ID " + id + ": " + title);
- NotificationManager.from(context).notify(TAG, id, builder.build());
+ sendForegroundabledNotification(id, builder.build());
}
private static Notification.Builder newBaseNotification(Context context) {
@@ -999,13 +1047,13 @@
/**
* Sends a zipped bugreport notification.
*/
- private static void sendZippedBugreportNotification(final Context context,
- final BugreportInfo info, final boolean takingScreenshot) {
+ private void sendZippedBugreportNotification( final BugreportInfo info,
+ final boolean takingScreenshot) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
zipBugreport(info);
- sendBugreportNotification(context, info, takingScreenshot);
+ sendBugreportNotification(info, takingScreenshot);
return null;
}
}.execute();
@@ -1043,7 +1091,7 @@
* If user provided a title, it will be saved into a {@code title.txt} entry; similarly, the
* description will be saved on {@code description.txt}.
*/
- private static void addDetailsToZipFile(Context context, BugreportInfo info) {
+ private void addDetailsToZipFile(BugreportInfo info) {
if (info.bugreportFile == null) {
// One possible reason is a bug in the Parcelization code.
Log.wtf(TAG, "addDetailsToZipFile(): no bugreportFile on " + info);
@@ -1061,7 +1109,8 @@
// It's not possible to add a new entry into an existing file, so we need to create a new
// zip, copy all entries, then rename it.
- sendBugreportBeingUpdatedNotification(context, info.id); // ...and that takes time
+ sendBugreportBeingUpdatedNotification(mContext, info.id); // ...and that takes time
+
final File dir = info.bugreportFile.getParentFile();
final File tmpZip = new File(dir, "tmp-" + info.bugreportFile.getName());
Log.d(TAG, "Writing temporary zip file (" + tmpZip + ") with title and/or description");
@@ -1084,16 +1133,18 @@
addEntry(zos, "title.txt", info.title);
addEntry(zos, "description.txt", info.description);
} catch (IOException e) {
- info.addingDetailsToZip = false;
Log.e(TAG, "exception zipping file " + tmpZip, e);
return;
+ } finally {
+ // Make sure it only tries to add details once, even it fails the first time.
+ info.addedDetailsToZip = true;
+ info.addingDetailsToZip = false;
+ stopForegroundWhenDone(info.id);
}
if (!tmpZip.renameTo(info.bugreportFile)) {
Log.e(TAG, "Could not rename " + tmpZip + " to " + info.bugreportFile);
}
- info.addedDetailsToZip = true;
- info.addingDetailsToZip = false;
}
private static void addEntry(ZipOutputStream zos, String entry, String text)
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index f76fb26..07c1546 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -241,14 +241,6 @@
}
public void testProgress_takeExtraScreenshot() throws Exception {
- takeExtraScreenshotTest(false);
- }
-
- public void testProgress_takeExtraScreenshotServiceDiesAfterScreenshotTaken() throws Exception {
- takeExtraScreenshotTest(true);
- }
-
- private void takeExtraScreenshotTest(boolean serviceDies) throws Exception {
resetProperties();
sendBugreportStarted(1000);
@@ -259,11 +251,6 @@
sendBugreportFinished(ID, mPlainTextPath, mScreenshotPath);
- if (serviceDies) {
- waitShareNotification(ID);
- killService();
- }
-
Bundle extras = acceptBugreportAndGetSharedIntent(ID);
assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, ZIP_FILE,
NAME, NO_TITLE, NO_DESCRIPTION, 1, RENAMED_SCREENSHOTS);
@@ -272,14 +259,6 @@
}
public void testScreenshotFinishesAfterBugreport() throws Exception {
- screenshotFinishesAfterBugreportTest(false);
- }
-
- public void testScreenshotFinishesAfterBugreportAndServiceDiesBeforeSharing() throws Exception {
- screenshotFinishesAfterBugreportTest(true);
- }
-
- private void screenshotFinishesAfterBugreportTest(boolean serviceDies) throws Exception {
resetProperties();
sendBugreportStarted(1000);
@@ -291,10 +270,6 @@
// There's no indication in the UI about the screenshot finish, so just sleep like a baby...
Thread.sleep(SAFE_SCREENSHOT_DELAY * DateUtils.SECOND_IN_MILLIS);
- if (serviceDies) {
- killService();
- }
-
Bundle extras = acceptBugreportAndGetSharedIntent(ID);
assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT, ID, PID, ZIP_FILE,
NAME, NO_TITLE, NO_DESCRIPTION, 1, RENAMED_SCREENSHOTS);
@@ -562,7 +537,7 @@
public void testShareBugreportAfterServiceDies() throws Exception {
sendBugreportFinished(NO_ID, mPlainTextPath, NO_SCREENSHOT);
- killService();
+ waitForService(false);
Bundle extras = acceptBugreportAndGetSharedIntent(NO_ID);
assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT);
}
@@ -841,15 +816,6 @@
assertFalse("Service '" + service + "' is still running", isServiceRunning(service));
}
- private void killService() {
- waitForService(true);
- Log.v(TAG, "Stopping service");
- boolean stopped = mContext.stopService(new Intent(mContext, BugreportProgressService.class));
- Log.d(TAG, "stopService returned " + stopped);
- waitForService(false);
- assertServiceNotRunning(); // Sanity check.
- }
-
private boolean isServiceRunning(String name) {
ActivityManager manager = (ActivityManager) mContext
.getSystemService(Context.ACTIVITY_SERVICE);
@@ -878,12 +844,6 @@
Thread.currentThread().interrupt();
}
}
- if (!expectRunning) {
- // Typically happens when service is waiting for a screenshot to finish.
- Log.w(TAG, "Service didn't stop; try to kill it again");
- killService();
- return;
- }
fail("Service status didn't change to " + expectRunning);
}
diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml
index e1424f0..f60a3b6 100644
--- a/packages/SystemUI/res/layout/notification_guts.xml
+++ b/packages/SystemUI/res/layout/notification_guts.xml
@@ -63,6 +63,7 @@
android:id="@+id/importance_buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginStart="-6dp"
android:paddingTop="4dp"
android:paddingEnd="8dp" >
<RadioButton
diff --git a/packages/SystemUI/res/layout/remote_input.xml b/packages/SystemUI/res/layout/remote_input.xml
index 7460201..2db97a6 100644
--- a/packages/SystemUI/res/layout/remote_input.xml
+++ b/packages/SystemUI/res/layout/remote_input.xml
@@ -22,8 +22,7 @@
android:theme="@style/systemui_theme_remote_input"
android:id="@+id/remote_input"
android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:paddingEnd="12dp">
+ android:layout_width="match_parent">
<view class="com.android.systemui.statusbar.policy.RemoteInputView$RemoteEditText"
android:id="@+id/remote_input_text"
@@ -48,19 +47,17 @@
<FrameLayout
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:paddingTop="2dp"
- android:paddingBottom="4dp">
+ android:layout_height="match_parent"
+ android:layout_gravity="center_vertical">
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingStart="12dp"
- android:paddingEnd="12dp"
- android:paddingTop="12dp"
- android:paddingBottom="12dp"
+ android:paddingEnd="24dp"
+ android:paddingTop="16dp"
+ android:paddingBottom="16dp"
android:id="@+id/remote_input_send"
android:src="@drawable/ic_send"
android:contentDescription="@*android:string/ime_action_send"
@@ -72,6 +69,7 @@
android:id="@+id/remote_input_progress"
android:layout_width="24dp"
android:layout_height="24dp"
+ android:layout_marginEnd="6dp"
android:layout_gravity="center"
android:visibility="invisible"
android:indeterminate="true"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index ccefb5f..658571e 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -39,8 +39,8 @@
android:clipToPadding="false"
android:clipChildren="false">
- <com.android.systemui.DensityContainer
- android:id="@+id/qs_density_container"
+ <com.android.systemui.AutoReinflateContainer
+ android:id="@+id/qs_auto_reinflate_container"
android:layout="@layout/qs_panel"
android:layout_width="@dimen/notification_panel_width"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/tv_pip_control_button.xml b/packages/SystemUI/res/layout/tv_pip_control_button.xml
index 0beeda1..f18a5da 100644
--- a/packages/SystemUI/res/layout/tv_pip_control_button.xml
+++ b/packages/SystemUI/res/layout/tv_pip_control_button.xml
@@ -38,5 +38,6 @@
android:alpha="0"
android:fontFamily="sans-serif"
android:textSize="12sp"
- android:textColor="#EEEEEE" />
+ android:textColor="#EEEEEE"
+ android:importantForAccessibility="no" />
</merge>
diff --git a/packages/SystemUI/res/layout/tv_pip_recents_overlay.xml b/packages/SystemUI/res/layout/tv_pip_recents_overlay.xml
index 1e464d8..4a67000 100644
--- a/packages/SystemUI/res/layout/tv_pip_recents_overlay.xml
+++ b/packages/SystemUI/res/layout/tv_pip_recents_overlay.xml
@@ -23,7 +23,7 @@
<com.android.systemui.tv.pip.PipRecentsControlsView
android:id="@+id/pip_controls"
android:layout_width="wrap_content"
- android:layout_height="match_parent" />
+ android:layout_height="wrap_content" />
<View
android:id="@+id/recents"
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index baec8ef..d3f2a25 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -29,15 +29,10 @@
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="8dp"
- android:paddingStart="8dp">
+ android:paddingStart="8dp"
+ android:animateLayoutChanges="true" >
<!-- volume rows added and removed here! :-) -->
- <LinearLayout
- android:id="@+id/volume_row_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginEnd="@dimen/volume_button_size"
- android:orientation="vertical"/>
<include layout="@layout/volume_zen_footer" />
diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml
index 57bac41..f0ae1c9 100644
--- a/packages/SystemUI/res/layout/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_row.xml
@@ -18,7 +18,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
- android:id="@+id/volume_dialog_row" >
+ android:id="@+id/volume_dialog_row"
+ android:paddingEnd="@dimen/volume_button_size" >
<TextView
android:id="@+id/volume_row_header"
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 1543360..4306fcc 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -98,7 +98,7 @@
<attr name="metricsAction" format="integer" />
</declare-styleable>
- <declare-styleable name="DensityContainer">
+ <declare-styleable name="AutoReinflateContainer">
<attr name="android:layout" />
</declare-styleable>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index ea55ac2..981b2dd 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -381,6 +381,9 @@
<!-- Content description of the battery level icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_battery_level">Battery <xliff:g id="number">%d</xliff:g> percent.</string>
+ <!-- Content description of the battery level icon for accessibility while the device is charging (not shown on the screen). [CHAR LIMIT=NONE] -->
+ <string name="accessibility_battery_level_charging">Battery charging, <xliff:g id="battery_percentage">%d</xliff:g> percent.</string>
+
<!-- Content description of the button for showing a settings panel in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_settings_button">System settings.</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index aeb484f..5e8162e 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -350,7 +350,7 @@
</style>
<style name="TextAppearance.NotificationGuts.Radio">
- <item name="android:alpha">.87</item>
+ <item name="android:alpha">.54</item>
</style>
<style name="TextAppearance.NotificationGuts.Button">
diff --git a/packages/SystemUI/src/com/android/systemui/DensityContainer.java b/packages/SystemUI/src/com/android/systemui/AutoReinflateContainer.java
similarity index 66%
rename from packages/SystemUI/src/com/android/systemui/DensityContainer.java
rename to packages/SystemUI/src/com/android/systemui/AutoReinflateContainer.java
index 2e3cb49..0afab88 100644
--- a/packages/SystemUI/src/com/android/systemui/DensityContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/AutoReinflateContainer.java
@@ -19,6 +19,7 @@
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.util.AttributeSet;
+import android.util.LocaleList;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
@@ -26,31 +27,47 @@
import java.util.ArrayList;
import java.util.List;
-public class DensityContainer extends FrameLayout {
+/**
+ * Custom {@link FrameLayout} that re-inflates when changes to {@link Configuration} happen.
+ * Currently supports changes to density and locale.
+ */
+public class AutoReinflateContainer extends FrameLayout {
private final List<InflateListener> mInflateListeners = new ArrayList<>();
private final int mLayout;
private int mDensity;
+ private LocaleList mLocaleList;
- public DensityContainer(Context context, @Nullable AttributeSet attrs) {
+ public AutoReinflateContainer(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mDensity = context.getResources().getConfiguration().densityDpi;
+ mLocaleList = context.getResources().getConfiguration().getLocales();
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DensityContainer);
- if (!a.hasValue(R.styleable.DensityContainer_android_layout)) {
- throw new IllegalArgumentException("DensityContainer must contain a layout");
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AutoReinflateContainer);
+ if (!a.hasValue(R.styleable.AutoReinflateContainer_android_layout)) {
+ throw new IllegalArgumentException("AutoReinflateContainer must contain a layout");
}
- mLayout = a.getResourceId(R.styleable.DensityContainer_android_layout, 0);
+ mLayout = a.getResourceId(R.styleable.AutoReinflateContainer_android_layout, 0);
inflateLayout();
}
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- int density = newConfig.densityDpi;
+ boolean shouldInflateLayout = false;
+ final int density = newConfig.densityDpi;
if (density != mDensity) {
mDensity = density;
+ shouldInflateLayout = true;
+ }
+ final LocaleList localeList = newConfig.getLocales();
+ if (localeList != mLocaleList) {
+ mLocaleList = localeList;
+ shouldInflateLayout = true;
+ }
+
+ if (shouldInflateLayout) {
inflateLayout();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 0bf81e9..d8b95cc 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -89,7 +89,8 @@
@Override
public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
setContentDescription(
- getContext().getString(R.string.accessibility_battery_level, level));
+ getContext().getString(charging ? R.string.accessibility_battery_level_charging
+ : R.string.accessibility_battery_level, level));
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
index 5e35d76..851ab77 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
@@ -67,7 +67,7 @@
// If the phone is rotated to landscape, the calculations would be wrong if xdpi and ydpi
// were to be used separately. Due negligible differences in xdpi and ydpi we can just
// take the average.
- // TODO: make this respect DPI changes.
+ // Note that xdpi and ydpi are the physical pixels per inch and are not affected by scaling.
mDpi = (displayMetrics.xdpi + displayMetrics.ydpi) / 2.0f;
mClassifierData = new ClassifierData(mDpi);
mHistoryEvaluator = new HistoryEvaluator();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
index 7378102..4a8abf7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
@@ -26,6 +26,7 @@
import android.view.View;
import android.view.ViewTreeObserver.OnPreDrawListener;
import android.view.WindowManager;
+import android.view.accessibility.AccessibilityEvent;
import android.widget.FrameLayout.LayoutParams;
import com.android.systemui.R;
@@ -131,6 +132,7 @@
@Override
public void onRecentsFocused() {
mRecentsView.requestFocus();
+ mRecentsView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
}
};
private final View.OnFocusChangeListener mPipViewFocusChangeListener =
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 44a167b..9fd4b05 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -32,7 +32,6 @@
import android.hardware.display.DisplayManager;
import android.os.Bundle;
import android.util.AttributeSet;
-import android.util.MutableInt;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.GestureDetector;
@@ -105,6 +104,8 @@
new PathInterpolator(0.5f, 1f, 0.5f, 1f);
private static final PathInterpolator DIM_INTERPOLATOR =
new PathInterpolator(.23f, .87f, .52f, -0.11f);
+ private static final Interpolator IME_ADJUST_INTERPOLATOR =
+ new PathInterpolator(0.2f, 0f, 0.1f, 1f);
private DividerHandleView mHandle;
private View mBackground;
@@ -701,7 +702,7 @@
resetBackground();
} else if (mDockSide == WindowManager.DOCKED_TOP) {
mBackground.setPivotY(0);
- mBackground.setScaleY(MINIMIZE_DOCK_SCALE);
+ mBackground.setScaleY(ADJUSTED_FOR_IME_SCALE);
}
mAdjustedForIme = adjustedForIme;
}
@@ -709,20 +710,20 @@
public void setAdjustedForIme(boolean adjustedForIme, long animDuration) {
updateDockSide();
mHandle.animate()
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .setInterpolator(IME_ADJUST_INTERPOLATOR)
.setDuration(animDuration)
.alpha(adjustedForIme ? 0f : 1f)
.start();
if (mDockSide == WindowManager.DOCKED_TOP) {
mBackground.setPivotY(0);
mBackground.animate()
- .scaleY(adjustedForIme ? MINIMIZE_DOCK_SCALE : 1f);
+ .scaleY(adjustedForIme ? ADJUSTED_FOR_IME_SCALE : 1f);
}
if (!adjustedForIme) {
mBackground.animate().withEndAction(mResetBackgroundRunnable);
}
mBackground.animate()
- .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+ .setInterpolator(IME_ADJUST_INTERPOLATOR)
.setDuration(animDuration)
.start();
mAdjustedForIme = adjustedForIme;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 2d5b6d4..8bf32c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -537,8 +537,7 @@
);
}
} else if (WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION.equals(action)) {
- final IntentSender intentSender = (IntentSender) intent
- .getParcelableExtra(Intent.EXTRA_INTENT);
+ final IntentSender intentSender = intent.getParcelableExtra(Intent.EXTRA_INTENT);
final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
try {
mContext.startIntentSender(intentSender, null, 0, 0, 0);
@@ -1924,11 +1923,23 @@
callBackIntent.putExtra(Intent.EXTRA_INDEX, notificationKey);
callBackIntent.setPackage(mContext.getPackageName());
- newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- newIntent.putExtra(Intent.EXTRA_INTENT, PendingIntent
- .getBroadcast(mContext, 0, callBackIntent, 0).getIntentSender());
- mContext.startActivity(newIntent);
+ PendingIntent callBackPendingIntent = PendingIntent.getBroadcast(
+ mContext,
+ 0,
+ callBackIntent,
+ PendingIntent.FLAG_CANCEL_CURRENT |
+ PendingIntent.FLAG_ONE_SHOT |
+ PendingIntent.FLAG_IMMUTABLE
+ );
+ newIntent.putExtra(
+ Intent.EXTRA_INTENT,
+ callBackPendingIntent.getIntentSender()
+ );
+ try {
+ ActivityManagerNative.getDefault().startConfirmDeviceCredentialIntent(newIntent);
+ } catch (RemoteException ex) {
+ // ignore
+ }
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 48cf631..8617104 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -41,9 +41,9 @@
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
import com.android.keyguard.KeyguardStatusView;
+import com.android.systemui.AutoReinflateContainer;
+import com.android.systemui.AutoReinflateContainer.InflateListener;
import com.android.systemui.DejankUtils;
-import com.android.systemui.DensityContainer;
-import com.android.systemui.DensityContainer.InflateListener;
import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
import com.android.systemui.Interpolators;
@@ -92,7 +92,7 @@
private KeyguardUserSwitcher mKeyguardUserSwitcher;
private KeyguardStatusBarView mKeyguardStatusBar;
protected QSContainer mQsContainer;
- private DensityContainer mQsDensityContainer;
+ private AutoReinflateContainer mQsAutoReinflateContainer;
private KeyguardStatusView mKeyguardStatusView;
private TextView mClockView;
private View mReserveNotificationSpace;
@@ -219,8 +219,9 @@
super.onFinishInflate();
mKeyguardStatusBar = (KeyguardStatusBarView) findViewById(R.id.keyguard_header);
mKeyguardStatusView = (KeyguardStatusView) findViewById(R.id.keyguard_status_view);
- mQsDensityContainer = (DensityContainer) findViewById(R.id.qs_density_container);
- mQsDensityContainer.addInflateListener(new InflateListener() {
+ mQsAutoReinflateContainer =
+ (AutoReinflateContainer) findViewById(R.id.qs_auto_reinflate_container);
+ mQsAutoReinflateContainer.addInflateListener(new InflateListener() {
@Override
public void onInflated(View v) {
mQsContainer = (QSContainer) v.findViewById(R.id.quick_settings_container);
@@ -280,11 +281,11 @@
int panelWidth = getResources().getDimensionPixelSize(R.dimen.notification_panel_width);
int panelGravity = getResources().getInteger(R.integer.notification_panel_layout_gravity);
FrameLayout.LayoutParams lp =
- (FrameLayout.LayoutParams) mQsDensityContainer.getLayoutParams();
+ (FrameLayout.LayoutParams) mQsAutoReinflateContainer.getLayoutParams();
if (lp.width != panelWidth) {
lp.width = panelWidth;
lp.gravity = panelGravity;
- mQsDensityContainer.setLayoutParams(lp);
+ mQsAutoReinflateContainer.setLayoutParams(lp);
mQsContainer.post(mUpdateHeader);
}
@@ -790,8 +791,8 @@
}
private boolean isInQsArea(float x, float y) {
- return (x >= mQsDensityContainer.getX()
- && x <= mQsDensityContainer.getX() + mQsDensityContainer.getWidth())
+ return (x >= mQsAutoReinflateContainer.getX()
+ && x <= mQsAutoReinflateContainer.getX() + mQsAutoReinflateContainer.getWidth())
&& (y <= mNotificationStackScroller.getBottomMostNotificationBottom()
|| y <= mQsContainer.getY() + mQsContainer.getHeight());
}
@@ -1339,8 +1340,8 @@
return false;
}
View header = mKeyguardShowing ? mKeyguardStatusBar : mQsContainer.getHeader();
- boolean onHeader = x >= mQsDensityContainer.getX()
- && x <= mQsDensityContainer.getX() + mQsDensityContainer.getWidth()
+ boolean onHeader = x >= mQsAutoReinflateContainer.getX()
+ && x <= mQsAutoReinflateContainer.getX() + mQsAutoReinflateContainer.getWidth()
&& y >= header.getTop() && y <= header.getBottom();
if (mQsExpanded) {
return onHeader || (yDiff < 0 && isInQsArea(x, y));
@@ -2227,7 +2228,7 @@
protected void setVerticalPanelTranslation(float translation) {
mNotificationStackScroller.setTranslationX(translation);
- mQsDensityContainer.setTranslationX(translation);
+ mQsAutoReinflateContainer.setTranslationX(translation);
}
protected void updateStackHeight(float stackHeight) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
index 35fb2a5..36e59db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -24,7 +24,7 @@
import android.view.ViewStub;
import android.view.WindowInsets;
import android.widget.FrameLayout;
-import com.android.systemui.DensityContainer;
+import com.android.systemui.AutoReinflateContainer;
import com.android.systemui.R;
import com.android.systemui.qs.QSContainer;
import com.android.systemui.qs.customize.QSCustomizer;
@@ -33,10 +33,10 @@
* The container with notification stack scroller and quick settings inside.
*/
public class NotificationsQuickSettingsContainer extends FrameLayout
- implements ViewStub.OnInflateListener, DensityContainer.InflateListener {
+ implements ViewStub.OnInflateListener, AutoReinflateContainer.InflateListener {
- private DensityContainer mQsContainer;
+ private AutoReinflateContainer mQsContainer;
private View mUserSwitcher;
private View mStackScroller;
private View mKeyguardStatusBar;
@@ -54,7 +54,7 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mQsContainer = (DensityContainer) findViewById(R.id.qs_density_container);
+ mQsContainer = (AutoReinflateContainer) findViewById(R.id.qs_auto_reinflate_container);
mQsContainer.addInflateListener(this);
mStackScroller = findViewById(R.id.notification_stack_scroller);
mStackScrollerMargin = ((LayoutParams) mStackScroller.getLayoutParams()).bottomMargin;
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 712f814..c36c482 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -103,10 +103,10 @@
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.ViewMediatorCallback;
+import com.android.systemui.AutoReinflateContainer;
+import com.android.systemui.AutoReinflateContainer.InflateListener;
import com.android.systemui.BatteryMeterView;
import com.android.systemui.DemoMode;
-import com.android.systemui.DensityContainer;
-import com.android.systemui.DensityContainer.InflateListener;
import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
import com.android.systemui.Interpolators;
@@ -871,8 +871,8 @@
}
// Set up the quick settings tile panel
- DensityContainer container = (DensityContainer) mStatusBarWindow.findViewById(
- R.id.qs_density_container);
+ AutoReinflateContainer container = (AutoReinflateContainer) mStatusBarWindow.findViewById(
+ R.id.qs_auto_reinflate_container);
if (container != null) {
final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this,
mBluetoothController, mLocationController, mRotationLockController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index 3293964..66152fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -61,6 +61,7 @@
private Calendar mCalendar;
private String mClockFormatString;
private SimpleDateFormat mClockFormat;
+ private SimpleDateFormat mContentDescriptionFormat;
private Locale mLocale;
private static final int AM_PM_STYLE_NORMAL = 0;
@@ -158,6 +159,7 @@
if (mDemoMode) return;
mCalendar.setTimeInMillis(System.currentTimeMillis());
setText(getSmallTime());
+ setContentDescription(mContentDescriptionFormat.format(mCalendar.getTime()));
}
@Override
@@ -207,6 +209,7 @@
? is24 ? d.timeFormat_Hms : d.timeFormat_hms
: is24 ? d.timeFormat_Hm : d.timeFormat_hm;
if (!format.equals(mClockFormatString)) {
+ mContentDescriptionFormat = new SimpleDateFormat(format);
/*
* Search for an unquoted "a" in the format string, so we can
* add dummy characters around it to let us find it again after
@@ -295,6 +298,7 @@
mCalendar.set(Calendar.MINUTE, mm);
}
setText(getSmallTime());
+ setContentDescription(mContentDescriptionFormat.format(mCalendar.getTime()));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 557f166..ecd1772 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -105,7 +105,6 @@
return false;
}
});
- mEditText.setOnClickListener(this);
mEditText.addTextChangedListener(this);
mEditText.setInnerFocusable(false);
mEditText.mRemoteInputView = this;
@@ -148,15 +147,19 @@
@Override
public void onClick(View v) {
- if (v == mEditText) {
- if (!mEditText.isFocusable()) {
- focus();
- }
- } else if (v == mSendButton) {
+ if (v == mSendButton) {
sendRemoteInput();
}
}
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ super.onTouchEvent(event);
+
+ // We never want for a touch to escape to an outer view or one we covered.
+ return true;
+ }
+
public void onDefocus() {
mController.removeRemoteInput(mEntry);
mEntry.remoteInputText = mEditText.getText();
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlButtonView.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlButtonView.java
index c65415e..bcf2f67 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlButtonView.java
@@ -92,8 +92,8 @@
TypedArray typedArray =
context.obtainStyledAttributes(attrs, values, defStyleAttr, defStyleRes);
- mButtonImageView.setImageDrawable(typedArray.getDrawable(0));
- mDescriptionTextView.setText(typedArray.getText(1));
+ setImageResource(typedArray.getResourceId(0, 0));
+ setText(typedArray.getResourceId(1, 0));
typedArray.recycle();
}
@@ -132,6 +132,7 @@
* Sets the text for description the with the given resource id.
*/
public void setText(int resId) {
+ mButtonImageView.setContentDescription(getContext().getString(resId));
mDescriptionTextView.setText(resId);
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
index 5febb9b..d7efca7 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
@@ -276,9 +276,6 @@
void movePipToFullscreen() {
mState = STATE_NO_PIP;
mPipTaskId = TASK_ID_NO_PIP;
- for (int i = mListeners.size() - 1; i >= 0; --i) {
- mListeners.get(i).onMoveToFullscreen();
- }
resizePinnedStack(mState);
}
@@ -638,6 +635,11 @@
public void onPinnedStackAnimationEnded() {
if (DEBUG) Log.d(TAG, "onPinnedStackAnimationEnded()");
switch (mState) {
+ case STATE_NO_PIP:
+ for (int i = mListeners.size() - 1; i >= 0; --i) {
+ mListeners.get(i).onMoveToFullscreen();
+ }
+ break;
case STATE_PIP_OVERLAY:
if (!mPipRecentsOverlayManager.isRecentsShown()) {
showPipOverlay();
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
index d75561b..dd12360 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
@@ -21,6 +21,7 @@
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
import android.view.WindowManager.LayoutParams;
import android.view.WindowManager;
@@ -133,7 +134,7 @@
*/
public void requestFocus(boolean allowRecentsFocusable) {
mRecentsView.setVisibility(allowRecentsFocusable ? View.VISIBLE : View.GONE);
- if (!mIsRecentsShown || mIsPipFocusedInRecent) {
+ if (!mIsPipRecentsOverlayShown || !mIsRecentsShown || mIsPipFocusedInRecent) {
return;
}
mIsPipFocusedInRecent = true;
@@ -141,6 +142,7 @@
mWindowManager.updateViewLayout(mOverlayView, mPipRecentsControlsViewFocusedLayoutParams);
mPipControlsView.requestFocus();
+ mPipControlsView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
mPipControlsView.startFocusGainAnimation();
}
@@ -151,7 +153,7 @@
* This should be called only by {@link com.android.systemui.recents.tv.RecentsTvActivity}.
*/
public void clearFocus() {
- if (!mIsRecentsShown || !mIsPipFocusedInRecent) {
+ if (!mIsPipRecentsOverlayShown || !mIsRecentsShown || !mIsPipFocusedInRecent) {
return;
}
if (!mRecentsView.hasFocus()) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index 91a8493..0153a40 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -18,6 +18,7 @@
import android.accessibilityservice.AccessibilityServiceInfo;
import android.animation.LayoutTransition;
+import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.app.Dialog;
@@ -59,6 +60,7 @@
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
+import android.view.animation.DecelerateInterpolator;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.SeekBar;
@@ -92,6 +94,7 @@
public static final String SHOW_FULL_ZEN = "sysui_show_full_zen";
private static final long USER_ATTEMPT_GRACE_PERIOD = 1000;
+ private static final int UPDATE_ANIMATION_DURATION = 80;
private final Context mContext;
private final H mHandler = new H();
@@ -100,7 +103,6 @@
private CustomDialog mDialog;
private ViewGroup mDialogView;
private ViewGroup mDialogContentView;
- private ViewGroup mVolumeRowContainer;
private ImageButton mExpandButton;
private final List<VolumeRow> mRows = new ArrayList<>();
private final SpTexts mSpTexts;
@@ -207,8 +209,6 @@
}
});
mDialogContentView = (ViewGroup) mDialog.findViewById(R.id.volume_dialog_content);
- mVolumeRowContainer =
- (ViewGroup) mDialogContentView.findViewById(R.id.volume_row_container);
mExpanded = false;
mExpandButton = (ImageButton) mDialogView.findViewById(R.id.volume_expand_button);
mExpandButton.setOnClickListener(mClickExpand);
@@ -309,7 +309,7 @@
if (!mRows.isEmpty()) {
addSpacer(row);
}
- mVolumeRowContainer.addView(row.view);
+ mDialogContentView.addView(row.view, mDialogContentView.getChildCount() - 2);
mRows.add(row);
}
@@ -321,7 +321,7 @@
if (i > 0) {
addSpacer(row);
}
- mVolumeRowContainer.addView(row.view);
+ mDialogContentView.addView(row.view, mDialogContentView.getChildCount() - 2);
}
}
@@ -332,7 +332,7 @@
.getDimensionPixelSize(R.dimen.volume_slider_interspacing);
final LinearLayout.LayoutParams lp =
new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, h);
- mVolumeRowContainer.addView(v, lp);
+ mDialogContentView.addView(v, mDialogContentView.getChildCount() - 2, lp);
row.space = v;
}
@@ -372,6 +372,14 @@
writer.println(mAccessibility.mFeedbackEnabled);
}
+ private static int getImpliedLevel(SeekBar seekBar, int progress) {
+ final int m = seekBar.getMax();
+ final int n = m / 100 - 1;
+ final int level = progress == 0 ? 0
+ : progress == m ? (m / 100) : (1 + (int)((progress / (float) m) * n));
+ return level;
+ }
+
@SuppressLint("InflateParams")
private void initRow(final VolumeRow row, final int stream, int iconRes, int iconMuteRes,
boolean important) {
@@ -613,8 +621,8 @@
if (row.ss == null || !row.ss.dynamic) continue;
if (!mDynamic.get(row.stream)) {
mRows.remove(i);
- mVolumeRowContainer.removeView(row.view);
- mVolumeRowContainer.removeView(row.space);
+ mDialogContentView.removeView(row.view);
+ mDialogContentView.removeView(row.space);
}
}
}
@@ -710,7 +718,7 @@
: false;
// update slider max
- final int max = ss.levelMax;
+ final int max = ss.levelMax * 100;
if (max != row.slider.getMax()) {
row.slider.setMax(max);
}
@@ -827,7 +835,8 @@
if (row.tracking) {
return; // don't update if user is sliding
}
- final int level = row.slider.getProgress();
+ final int progress = row.slider.getProgress();
+ final int level = getImpliedLevel(row.slider, progress);
final boolean rowVisible = row.view.getVisibility() == View.VISIBLE;
final boolean inGracePeriod = (SystemClock.uptimeMillis() - row.userAttempt)
< USER_ATTEMPT_GRACE_PERIOD;
@@ -843,7 +852,33 @@
return; // don't clamp if visible
}
}
- row.slider.setProgress(vlevel, true);
+ final int newProgress = vlevel * 100;
+ if (progress != newProgress) {
+ if (mShowing && rowVisible) {
+ // animate!
+ if (row.anim != null && row.anim.isRunning()
+ && row.animTargetProgress == newProgress) {
+ return; // already animating to the target progress
+ }
+ // start/update animation
+ if (row.anim == null) {
+ row.anim = ObjectAnimator.ofInt(row.slider, "progress", progress, newProgress);
+ row.anim.setInterpolator(new DecelerateInterpolator());
+ } else {
+ row.anim.cancel();
+ row.anim.setIntValues(progress, newProgress);
+ }
+ row.animTargetProgress = newProgress;
+ row.anim.setDuration(UPDATE_ANIMATION_DURATION);
+ row.anim.start();
+ } else {
+ // update slider directly to clamped value
+ if (row.anim != null) {
+ row.anim.cancel();
+ }
+ row.slider.setProgress(newProgress);
+ }
+ }
}
private void recheckH(VolumeRow row) {
@@ -1063,19 +1098,20 @@
+ " onProgressChanged " + progress + " fromUser=" + fromUser);
if (!fromUser) return;
if (mRow.ss.levelMin > 0) {
- final int minProgress = mRow.ss.levelMin;
+ final int minProgress = mRow.ss.levelMin * 100;
if (progress < minProgress) {
seekBar.setProgress(minProgress);
progress = minProgress;
}
}
- if (mRow.ss.level != progress || mRow.ss.muted && progress > 0) {
+ final int userLevel = getImpliedLevel(seekBar, progress);
+ if (mRow.ss.level != userLevel || mRow.ss.muted && userLevel > 0) {
mRow.userAttempt = SystemClock.uptimeMillis();
- if (mRow.requestedLevel != progress) {
- mController.setStreamVolume(mRow.stream, progress);
- mRow.requestedLevel = progress;
+ if (mRow.requestedLevel != userLevel) {
+ mController.setStreamVolume(mRow.stream, userLevel);
+ mRow.requestedLevel = userLevel;
Events.writeEvent(mContext, Events.EVENT_TOUCH_LEVEL_CHANGED, mRow.stream,
- progress);
+ userLevel);
}
}
}
@@ -1092,7 +1128,7 @@
if (D.BUG) Log.d(TAG, "onStopTrackingTouch"+ " " + mRow.stream);
mRow.tracking = false;
mRow.userAttempt = SystemClock.uptimeMillis();
- final int userLevel = seekBar.getProgress();
+ final int userLevel = getImpliedLevel(seekBar, seekBar.getProgress());
Events.writeEvent(mContext, Events.EVENT_TOUCH_LEVEL_DONE, mRow.stream, userLevel);
if (mRow.ss.level != userLevel) {
mHandler.sendMessageDelayed(mHandler.obtainMessage(H.RECHECK, mRow),
@@ -1172,6 +1208,8 @@
private ColorStateList cachedSliderTint;
private int iconState; // from Events
private boolean cachedShowHeaders = VolumePrefs.DEFAULT_SHOW_HEADERS;
+ private ObjectAnimator anim; // slider progress animation for non-touch-related updates
+ private int animTargetProgress;
private int lastAudibleLevel = 1;
}
diff --git a/packages/WallpaperBackup/Android.mk b/packages/WallpaperBackup/Android.mk
new file mode 100644
index 0000000..cf04249
--- /dev/null
+++ b/packages/WallpaperBackup/Android.mk
@@ -0,0 +1,34 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+
+LOCAL_PACKAGE_NAME := WallpaperBackup
+LOCAL_CERTIFICATE := platform
+LOCAL_PRIVILEGED_MODULE := false
+
+include $(BUILD_PACKAGE)
+
+########################
+include $(call all-makefiles-under,$(LOCAL_PATH))
+
diff --git a/packages/WallpaperBackup/AndroidManifest.xml b/packages/WallpaperBackup/AndroidManifest.xml
new file mode 100644
index 0000000..b8cea20
--- /dev/null
+++ b/packages/WallpaperBackup/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2016 Google Inc.
+ *
+ * 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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.wallpaperbackup"
+ android:sharedUserId="android.uid.system" >
+
+ <application android:allowClearUserData="false"
+ android:process="system"
+ android:killAfterRestore="false"
+ android:allowBackup="true"
+ android:backupAgent=".WallpaperBackupAgent"
+ android:fullBackupOnly="true" >
+ </application>
+</manifest>
diff --git a/packages/WallpaperBackup/proguard.flags b/packages/WallpaperBackup/proguard.flags
new file mode 100644
index 0000000..247e6ef
--- /dev/null
+++ b/packages/WallpaperBackup/proguard.flags
@@ -0,0 +1 @@
+-keep class com.android.wallpaperbackup.WallpaperBackupAgent
diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
new file mode 100644
index 0000000..2f79079
--- /dev/null
+++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
@@ -0,0 +1,164 @@
+/*
+ * 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.wallpaperbackup;
+
+import android.app.WallpaperManager;
+import android.app.backup.BackupAgent;
+import android.app.backup.BackupDataInput;
+import android.app.backup.BackupDataOutput;
+import android.app.backup.FullBackupDataOutput;
+import android.content.Context;
+import android.os.Environment;
+import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
+import android.system.Os;
+import android.util.Slog;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+public class WallpaperBackupAgent extends BackupAgent {
+ private static final String TAG = "WallpaperBackup";
+ private static final boolean DEBUG = false;
+
+ // NB: must be kept in sync with WallpaperManagerService but has no
+ // compile-time visiblity.
+
+ // Target filenames within the system's wallpaper directory
+ static final String WALLPAPER = "wallpaper_orig";
+ static final String WALLPAPER_INFO = "wallpaper_info.xml";
+
+ // Names of our local-data stage files/links
+ static final String IMAGE_STAGE = "wallpaper-stage";
+ static final String INFO_STAGE = "wallpaper-info-stage";
+ static final String EMPTY_SENTINEL = "empty";
+
+ private File mWallpaperInfo; // wallpaper metadata file
+ private File mWallpaperFile; // primary wallpaper image file
+
+ private WallpaperManager mWm;
+
+ @Override
+ public void onCreate() {
+ if (DEBUG) {
+ Slog.v(TAG, "onCreate()");
+ }
+
+ File wallpaperDir = Environment.getUserSystemDirectory(UserHandle.USER_SYSTEM);
+ mWallpaperInfo = new File(wallpaperDir, WALLPAPER_INFO);
+ mWallpaperFile = new File(wallpaperDir, WALLPAPER);
+ mWm = (WallpaperManager) getSystemService(Context.WALLPAPER_SERVICE);
+ }
+
+ @Override
+ public void onFullBackup(FullBackupDataOutput data) throws IOException {
+ // To avoid data duplication and disk churn, use links as the stage.
+ final File filesDir = getFilesDir();
+ final File infoStage = new File(filesDir, INFO_STAGE);
+ final File imageStage = new File (filesDir, IMAGE_STAGE);
+ final File empty = new File (filesDir, EMPTY_SENTINEL);
+
+ try {
+ // We always back up this 'empty' file to ensure that the absence of
+ // storable wallpaper imagery still produces a non-empty backup data
+ // stream, otherwise it'd simply be ignored in preflight.
+ FileOutputStream touch = new FileOutputStream(empty);
+ touch.close();
+ fullBackupFile(empty, data);
+
+ // only back up the wallpaper if we've been told it's allowed
+ if (mWm.isWallpaperBackupEligible()) {
+ if (DEBUG) {
+ Slog.v(TAG, "Wallpaper is backup-eligible; linking & writing");
+ }
+ Os.link(mWallpaperInfo.getCanonicalPath(), infoStage.getCanonicalPath());
+ fullBackupFile(infoStage, data);
+ Os.link(mWallpaperFile.getCanonicalPath(), imageStage.getCanonicalPath());
+ fullBackupFile(imageStage, data);
+ } else {
+ if (DEBUG) {
+ Slog.v(TAG, "Wallpaper not backup-eligible; writing no data");
+ }
+ }
+ } catch (Exception e) {
+ Slog.e(TAG, "Unable to back up wallpaper: " + e.getMessage());
+ } finally {
+ if (DEBUG) {
+ Slog.v(TAG, "Removing backup stage links");
+ }
+ infoStage.delete();
+ imageStage.delete();
+ }
+ }
+
+ // We use the default onRestoreFile() implementation that will recreate our stage files,
+ // then postprocess in onRestoreFinished() to move them on top of the live data.
+ //
+ // NOTE: this relies on our local files dir being on the same filesystem as the live
+ // system wallpaper data. If this is not the case then an actual copy operation will
+ // be needed.
+ @Override
+ public void onRestoreFinished() {
+ if (DEBUG) {
+ Slog.v(TAG, "onRestoreFinished()");
+ }
+ final File infoStage = new File(getFilesDir(), INFO_STAGE);
+ final File imageStage = new File (getFilesDir(), IMAGE_STAGE);
+
+ try {
+ // It is valid for the imagery to be absent; it means that we were not permitted
+ // to back up the original image on the source device.
+ if (imageStage.exists()) {
+ if (DEBUG) {
+ Slog.v(TAG, "Got restored wallpaper; renaming into place");
+ }
+ // Rename the image file into place last because that is the trigger for
+ // the wallpaper observer to generate a new crop/scale
+ Os.rename(infoStage.getCanonicalPath(), mWallpaperInfo.getCanonicalPath());
+ Os.rename(imageStage.getCanonicalPath(), mWallpaperFile.getCanonicalPath());
+ }
+ } catch (Exception e) {
+ Slog.e(TAG, "Unable to restore wallpaper: " + e.getMessage());
+ mWm.clearWallpaper(WallpaperManager.FLAG_SYSTEM, UserHandle.USER_SYSTEM);
+ } finally {
+ // These "should" not exist because of the renames, but make sure
+ // in case of errors/exceptions/etc.
+ if (DEBUG) {
+ Slog.v(TAG, "Removing restore stage files");
+ }
+ infoStage.delete();
+ imageStage.delete();
+ }
+ }
+
+ //
+ // Key/value API: abstract, so required, but not used
+ //
+
+ @Override
+ public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+ ParcelFileDescriptor newState) throws IOException {
+ // Intentionally blank
+ }
+
+ @Override
+ public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
+ throws IOException {
+ // Intentionally blank
+ }
+}
\ No newline at end of file
diff --git a/preloaded-classes b/preloaded-classes
index d854769..32b692a 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -1613,6 +1613,7 @@
android.os.AsyncTask$WorkerRunnable
android.os.BadParcelableException
android.os.BaseBundle
+android.os.BaseBundle$NoImagePreloadHolder
android.os.BatteryManager
android.os.Binder
android.os.BinderProxy
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 4d7f82d..2a7d945 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -20,6 +20,7 @@
import android.os.PowerManager;
import android.util.Pools.SimplePool;
import android.util.Slog;
+import android.util.SparseBooleanArray;
import android.view.Choreographer;
import android.view.InputDevice;
import android.view.InputEvent;
@@ -637,10 +638,10 @@
}
/**
- * Keeps state of stream of events from a keyboard device.
+ * Keeps state of streams of events from all keyboard devices.
*/
private static class KeyboardEventStreamState extends EventStreamState {
- private boolean mEventSequenceStarted;
+ private SparseBooleanArray mEventSequenceStartedMap = new SparseBooleanArray();
public KeyboardEventStreamState() {
reset();
@@ -649,17 +650,35 @@
@Override
final public void reset() {
super.reset();
- mEventSequenceStarted = false;
+ mEventSequenceStartedMap.clear();
}
+ /*
+ * Key events from different devices may be interleaved. For example, the volume up and
+ * down keys can come from different device IDs.
+ */
+ @Override
+ public boolean updateDeviceId(int deviceId) {
+ return false;
+ }
+
+ // We manage all device ids simultaneously; there is no concept of validity.
+ @Override
+ public boolean deviceIdValid() {
+ return true;
+ }
+
+
@Override
final public boolean shouldProcessKeyEvent(KeyEvent event) {
- // Wait for a down key event to start processing.
- if (mEventSequenceStarted) {
+ // For each keyboard device, wait for a down event from a device to start processing
+ int deviceId = event.getDeviceId();
+ if (mEventSequenceStartedMap.get(deviceId, false)) {
return true;
}
- mEventSequenceStarted = event.getAction() == KeyEvent.ACTION_DOWN;
- return mEventSequenceStarted;
+ boolean shouldProcess = event.getAction() == KeyEvent.ACTION_DOWN;
+ mEventSequenceStartedMap.put(deviceId, shouldProcess);
+ return shouldProcess;
}
}
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 71506be..b965f64 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -71,7 +71,7 @@
import android.net.RouteInfo;
import android.net.UidRange;
import android.net.Uri;
-import android.net.metrics.ConnectivityServiceChangeEvent;
+import android.net.metrics.DefaultNetworkEvent;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -2217,7 +2217,7 @@
rematchAllNetworksAndRequests(null, 0);
if (wasDefault && getDefaultNetwork() == null) {
// Log that we lost the default network and there is no replacement.
- logConnectivityServiceChangeEvent(null, nai);
+ logDefaultNetworkEvent(null, nai);
}
if (nai.created) {
// Tell netd to clean up the configuration for this network
@@ -2330,6 +2330,18 @@
if (VDBG || (DBG && nri.isRequest())) log("releasing NetworkRequest " + request);
nri.unlinkDeathRecipient();
mNetworkRequests.remove(request);
+ synchronized (mUidToNetworkRequestCount) {
+ int requests = mUidToNetworkRequestCount.get(nri.mUid, 0);
+ if (requests < 1) {
+ Slog.wtf(TAG, "BUG: too small request count " + requests + " for UID " +
+ nri.mUid);
+ } else if (requests == 1) {
+ mUidToNetworkRequestCount.removeAt(
+ mUidToNetworkRequestCount.indexOfKey(nri.mUid));
+ } else {
+ mUidToNetworkRequestCount.put(nri.mUid, requests - 1);
+ }
+ }
mNetworkRequestInfoLogs.log("RELEASE " + nri);
if (nri.isRequest()) {
// Find all networks that are satisfying this request and remove the request
@@ -3677,6 +3689,11 @@
private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests =
new HashMap<NetworkRequest, NetworkRequestInfo>();
+ private static final int MAX_NETWORK_REQUESTS_PER_UID = 100;
+ // Map from UID to number of NetworkRequests that UID has filed.
+ @GuardedBy("mUidToNetworkRequestCount")
+ private final SparseIntArray mUidToNetworkRequestCount = new SparseIntArray();
+
private static class NetworkFactoryInfo {
public final String name;
public final Messenger messenger;
@@ -3737,6 +3754,7 @@
mPid = getCallingPid();
mUid = getCallingUid();
mType = type;
+ enforceRequestCountLimit();
}
NetworkRequestInfo(Messenger m, NetworkRequest r, IBinder binder, NetworkRequestType type) {
@@ -3748,6 +3766,7 @@
mUid = getCallingUid();
mType = type;
mPendingIntent = null;
+ enforceRequestCountLimit();
try {
mBinder.linkToDeath(this, 0);
@@ -3756,6 +3775,16 @@
}
}
+ private void enforceRequestCountLimit() {
+ synchronized (mUidToNetworkRequestCount) {
+ int networkRequests = mUidToNetworkRequestCount.get(mUid, 0) + 1;
+ if (networkRequests >= MAX_NETWORK_REQUESTS_PER_UID) {
+ throw new IllegalArgumentException("Too many NetworkRequests filed");
+ }
+ mUidToNetworkRequestCount.put(mUid, networkRequests);
+ }
+ }
+
private String typeString() {
switch (mType) {
case LISTEN: return "Listen";
@@ -4452,8 +4481,7 @@
handleApplyDefaultProxy(newNetwork.linkProperties.getHttpProxy());
updateTcpBufferSizes(newNetwork);
setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers());
-
- logConnectivityServiceChangeEvent(newNetwork, prevNetwork);
+ logDefaultNetworkEvent(newNetwork, prevNetwork);
}
// Handles a network appearing or improving its score.
@@ -5075,21 +5103,24 @@
return new NetworkMonitor(context, handler, nai, defaultRequest);
}
- private static void logConnectivityServiceChangeEvent(
- NetworkAgentInfo next, NetworkAgentInfo prev) {
- final int newNetId = (next == null) ? NETID_UNSET : next.network.netId;
- final int[] newTransportTypes = (next == null)
- ? new int[0]
- : next.networkCapabilities.getTransportTypes();
+ private static void logDefaultNetworkEvent(NetworkAgentInfo newNai, NetworkAgentInfo prevNai) {
+ int newNetid = NETID_UNSET;
+ int prevNetid = NETID_UNSET;
+ int[] transports = new int[0];
+ boolean hadIPv4 = false;
+ boolean hadIPv6 = false;
- final int oldNetId = (prev == null) ? NETID_UNSET : prev.network.netId;
- final boolean hadIPv4 = (prev != null) &&
- prev.linkProperties.hasIPv4Address() &&
- prev.linkProperties.hasIPv4DefaultRoute();
- final boolean hadIPv6 = (prev != null) &&
- prev.linkProperties.hasGlobalIPv6Address() &&
- prev.linkProperties.hasIPv6DefaultRoute();
- ConnectivityServiceChangeEvent.logEvent(newNetId, newTransportTypes,
- oldNetId, hadIPv4, hadIPv6);
+ if (newNai != null) {
+ newNetid = newNai.network.netId;
+ transports = newNai.networkCapabilities.getTransportTypes();
+ }
+ if (prevNai != null) {
+ prevNetid = prevNai.network.netId;
+ final LinkProperties lp = prevNai.linkProperties;
+ hadIPv4 = lp.hasIPv4Address() && lp.hasIPv4DefaultRoute();
+ hadIPv6 = lp.hasGlobalIPv6Address() && lp.hasIPv6DefaultRoute();
+ }
+
+ DefaultNetworkEvent.logEvent(newNetid, transports, prevNetid, hadIPv4, hadIPv6);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d7afc13..3b024cf 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -11502,6 +11502,19 @@
}
@Override
+ public void startConfirmDeviceCredentialIntent(Intent intent) {
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "startConfirmDeviceCredentialIntent");
+ synchronized (this) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mActivityStarter.startConfirmCredentialIntent(intent);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ @Override
public void stopAppSwitches() {
if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
!= PackageManager.PERMISSION_GRANTED) {
@@ -17159,6 +17172,7 @@
|| Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action)
|| Intent.ACTION_GET_PERMISSIONS_COUNT.equals(action)
|| Intent.ACTION_GET_PERMISSIONS_PACKAGES.equals(action)
+ || Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(action)
|| AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
|| AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)
|| LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)) {
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 9c93f2c..4da6976 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -33,6 +33,7 @@
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
+import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
@@ -582,7 +583,7 @@
null /*voiceInteractor*/, null /*resultTo*/, null /*resultWho*/,
0 /*requestCode*/, 0 /*callingPid*/, 0 /*callingUid*/, null /*callingPackage*/,
0 /*realCallingPid*/, 0 /*realCallingUid*/, 0 /*startFlags*/, null /*options*/,
- false /*ignoreTargetSecurity*/, false /*componentSpecified*/, null /*outActivity*/,
+ false /*ignoreTargetSecurity*/, false /*componentSpecified*/, null /*outActivity*/,
null /*container*/, null /*inTask*/);
if (mSupervisor.inResumeTopActivity) {
// If we are in resume section already, home activity will be initialized, but not
@@ -612,11 +613,6 @@
.getSystemService(Context.KEYGUARD_SERVICE);
final Intent credential =
km.createConfirmDeviceCredentialIntent(null, null, userId);
- credential.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
- Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |
- Intent.FLAG_ACTIVITY_TASK_ON_HOME);
- final ActivityOptions options = ActivityOptions.makeBasic();
- options.setLaunchTaskId(mSupervisor.getHomeActivity().task.taskId);
final ActivityRecord activityRecord = targetStack.topRunningActivityLocked();
if (activityRecord != null) {
final IIntentSender target = mService.getIntentSenderLocked(
@@ -633,11 +629,19 @@
null);
credential.putExtra(Intent.EXTRA_INTENT, new IntentSender(target));
// Show confirm credentials activity.
- mService.mContext.startActivityAsUser(credential, options.toBundle(),
- UserHandle.CURRENT);
+ startConfirmCredentialIntent(credential);
}
}
+ void startConfirmCredentialIntent(Intent intent) {
+ intent.addFlags(FLAG_ACTIVITY_NEW_TASK |
+ FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |
+ FLAG_ACTIVITY_TASK_ON_HOME);
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchTaskId(mSupervisor.getHomeActivity().task.taskId);
+ mService.mContext.startActivityAsUser(intent, options.toBundle(),
+ UserHandle.CURRENT);
+ }
final int startActivityMayWait(IApplicationThread caller, int callingUid,
String callingPackage, Intent intent, String resolvedType,
@@ -1432,7 +1436,7 @@
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
if (!willClearTask) {
final ActivityStack launchStack = getLaunchStack(
- mStartActivity, mLaunchFlags, mStartActivity.task, mOptions, true);
+ mStartActivity, mLaunchFlags, mStartActivity.task, mOptions);
if (launchStack == null || launchStack == mTargetStack) {
// We only want to move to the front, if we aren't going to launch on a
// different stack. If we launch on a different stack, we will put the
@@ -1606,8 +1610,11 @@
// We only want to allow changing stack if the target task is not the top one,
// otherwise we would move the launching task to the other side, rather than show
// two side by side.
- final boolean launchToSideAllowed = sourceTask.stack.topTask() != sourceTask;
- mTargetStack = getLaunchStack(mStartActivity, mLaunchFlags, mStartActivity.task, mOptions, launchToSideAllowed);
+ final boolean moveStackAllowed = sourceTask.stack.topTask() != sourceTask;
+ if (moveStackAllowed) {
+ mTargetStack = getLaunchStack(mStartActivity, mLaunchFlags, mStartActivity.task,
+ mOptions);
+ }
if (mTargetStack == null) {
mTargetStack = sourceTask.stack;
@@ -1780,7 +1787,7 @@
return mSupervisor.mHomeStack;
}
- ActivityStack stack = getLaunchStack(r, launchFlags, task, aOptions, true);
+ ActivityStack stack = getLaunchStack(r, launchFlags, task, aOptions);
if (stack != null) {
return stack;
}
@@ -1845,7 +1852,7 @@
}
private ActivityStack getLaunchStack(ActivityRecord r, int launchFlags, TaskRecord task,
- ActivityOptions aOptions, boolean launchToSideAllowed) {
+ ActivityOptions aOptions) {
final int launchStackId =
(aOptions != null) ? aOptions.getLaunchStackId() : INVALID_STACK_ID;
@@ -1857,7 +1864,7 @@
return mSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
}
- if (!launchToSideAllowed || (launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) == 0) {
+ if ((launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) == 0) {
return null;
}
// Otherwise handle adjacent launch.
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index a2472ac..48fecd5 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -17,8 +17,6 @@
package com.android.server.am;
import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.ActivityManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Debug;
@@ -519,7 +517,7 @@
if (DEBUG) Slog.d(TAG, "removeObsoleteFiles: persistentTaskIds=" + persistentTaskIds +
" files=" + files);
if (files == null) {
- Slog.e(TAG, "File error accessing recents directory (too many files open?).");
+ Slog.e(TAG, "File error accessing recents directory (directory doesn't exist?).");
return;
}
for (int fileNdx = 0; fileNdx < files.length; ++fileNdx) {
@@ -597,15 +595,12 @@
}
static File getUserImagesDir(int userId) {
- File userImagesDir = new File(Environment.getDataSystemCeDirectory(userId), IMAGES_DIRNAME);
+ return new File(Environment.getDataSystemCeDirectory(userId), IMAGES_DIRNAME);
+ }
- if (!userImagesDir.exists()) {
- if (!userImagesDir.mkdir()) {
- Slog.e(TAG, "Failure creating images directory for user " + userId + ": "
- + userImagesDir);
- }
- }
- return userImagesDir;
+ private static boolean createParentDirectory(String filePath) {
+ File parentDir = new File(filePath).getParentFile();
+ return parentDir.exists() || parentDir.mkdirs();
}
private class LazyTaskWriterThread extends Thread {
@@ -693,6 +688,10 @@
if (item instanceof ImageWriteQueueItem) {
ImageWriteQueueItem imageWriteQueueItem = (ImageWriteQueueItem) item;
final String filePath = imageWriteQueueItem.mFilePath;
+ if (!createParentDirectory(filePath)) {
+ Slog.e(TAG, "Error while creating images directory for file: " + filePath);
+ continue;
+ }
final Bitmap bitmap = imageWriteQueueItem.mImage;
if (DEBUG) Slog.d(TAG, "writing bitmap: filename=" + filePath);
FileOutputStream imageFile = null;
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index d330756..381a110 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -36,8 +36,10 @@
import android.net.Uri;
import android.net.metrics.CaptivePortalCheckResultEvent;
import android.net.metrics.CaptivePortalStateChangeEvent;
+import android.net.metrics.NetworkMonitorEvent;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
+import android.net.util.Stopwatch;
import android.os.Handler;
import android.os.Message;
import android.os.Process;
@@ -79,7 +81,7 @@
*/
public class NetworkMonitor extends StateMachine {
private static final boolean DBG = false;
- private static final String TAG = "NetworkMonitor";
+ private static final String TAG = NetworkMonitor.class.getSimpleName();
private static final String DEFAULT_SERVER = "connectivitycheck.gstatic.com";
private static final int SOCKET_TIMEOUT_MS = 10000;
public static final String ACTION_NETWORK_CONDITIONS_MEASURED =
@@ -221,6 +223,7 @@
private final Context mContext;
private final Handler mConnectivityServiceHandler;
private final NetworkAgentInfo mNetworkAgentInfo;
+ private final int mNetId;
private final TelephonyManager mTelephonyManager;
private final WifiManager mWifiManager;
private final AlarmManager mAlarmManager;
@@ -246,6 +249,8 @@
private final LocalLog validationLogs = new LocalLog(20); // 20 lines
+ private final Stopwatch mEvaluationTimer = new Stopwatch();
+
public NetworkMonitor(Context context, Handler handler, NetworkAgentInfo networkAgentInfo,
NetworkRequest defaultRequest) {
// Add suffix indicating which NetworkMonitor we're talking about.
@@ -254,6 +259,7 @@
mContext = context;
mConnectivityServiceHandler = handler;
mNetworkAgentInfo = networkAgentInfo;
+ mNetId = mNetworkAgentInfo.network.netId;
mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
@@ -300,12 +306,12 @@
transitionTo(mLingeringState);
return HANDLED;
case CMD_NETWORK_CONNECTED:
- CaptivePortalStateChangeEvent.logEvent(
+ CaptivePortalStateChangeEvent.logEvent(mNetId,
CaptivePortalStateChangeEvent.NETWORK_MONITOR_CONNECTED);
transitionTo(mEvaluatingState);
return HANDLED;
case CMD_NETWORK_DISCONNECTED:
- CaptivePortalStateChangeEvent.logEvent(
+ CaptivePortalStateChangeEvent.logEvent(mNetId,
CaptivePortalStateChangeEvent.NETWORK_MONITOR_DISCONNECTED);
if (mLaunchCaptivePortalAppBroadcastReceiver != null) {
mContext.unregisterReceiver(mLaunchCaptivePortalAppBroadcastReceiver);
@@ -336,7 +342,7 @@
mUserDoesNotWant = true;
mConnectivityServiceHandler.sendMessage(obtainMessage(
EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID,
- mNetworkAgentInfo.network.netId, null));
+ mNetId, null));
// TODO: Should teardown network.
mUidResponsibleForReeval = 0;
transitionTo(mEvaluatingState);
@@ -356,7 +362,11 @@
private class ValidatedState extends State {
@Override
public void enter() {
- CaptivePortalStateChangeEvent.logEvent(
+ if (mEvaluationTimer.isRunning()) {
+ NetworkMonitorEvent.logValidated(mNetId, mEvaluationTimer.stop());
+ mEvaluationTimer.reset();
+ }
+ CaptivePortalStateChangeEvent.logEvent(mNetId,
CaptivePortalStateChangeEvent.NETWORK_MONITOR_VALIDATED);
mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
NETWORK_TEST_RESULT_VALID, mNetworkAgentInfo.network.netId, null));
@@ -436,6 +446,12 @@
@Override
public void enter() {
+ // If we have already started to track time spent in EvaluatingState
+ // don't reset the timer due simply to, say, commands or events that
+ // cause us to exit and re-enter EvaluatingState.
+ if (!mEvaluationTimer.isStarted()) {
+ mEvaluationTimer.start();
+ }
sendMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
if (mUidResponsibleForReeval != INVALID_UID) {
TrafficStats.setThreadStatsUid(mUidResponsibleForReeval);
@@ -481,22 +497,20 @@
// will be unresponsive. isCaptivePortal() could be executed on another Thread
// if this is found to cause problems.
CaptivePortalProbeResult probeResult = isCaptivePortal();
- CaptivePortalCheckResultEvent.logEvent(mNetworkAgentInfo.network.netId,
- probeResult.mHttpResponseCode);
+ CaptivePortalCheckResultEvent.logEvent(mNetId, probeResult.mHttpResponseCode);
if (probeResult.mHttpResponseCode == 204) {
transitionTo(mValidatedState);
} else if (probeResult.mHttpResponseCode >= 200 &&
probeResult.mHttpResponseCode <= 399) {
mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
- NETWORK_TEST_RESULT_INVALID, mNetworkAgentInfo.network.netId,
- probeResult.mRedirectUrl));
+ NETWORK_TEST_RESULT_INVALID, mNetId, probeResult.mRedirectUrl));
transitionTo(mCaptivePortalState);
} else {
final Message msg = obtainMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
sendMessageDelayed(msg, mReevaluateDelayMs);
mConnectivityServiceHandler.sendMessage(obtainMessage(
- EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID,
- mNetworkAgentInfo.network.netId, probeResult.mRedirectUrl));
+ EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID, mNetId,
+ probeResult.mRedirectUrl));
if (mAttempts >= BLAME_FOR_EVALUATION_ATTEMPTS) {
// Don't continue to blame UID forever.
TrafficStats.clearThreadStatsUid();
@@ -511,7 +525,7 @@
// Before IGNORE_REEVALUATE_ATTEMPTS attempts are made,
// ignore any re-evaluation requests. After, restart the
// evaluation process via EvaluatingState#enter.
- return mAttempts < IGNORE_REEVALUATE_ATTEMPTS ? HANDLED : NOT_HANDLED;
+ return (mAttempts < IGNORE_REEVALUATE_ATTEMPTS) ? HANDLED : NOT_HANDLED;
default:
return NOT_HANDLED;
}
@@ -553,6 +567,10 @@
@Override
public void enter() {
+ if (mEvaluationTimer.isRunning()) {
+ NetworkMonitorEvent.logCaptivePortalFound(mNetId, mEvaluationTimer.stop());
+ mEvaluationTimer.reset();
+ }
// Don't annoy user with sign-in notifications.
if (mDontDisplaySigninNotification) return;
// Create a CustomIntentReceiver that sends us a
@@ -593,7 +611,8 @@
@Override
public void enter() {
- final String cmdName = ACTION_LINGER_EXPIRED + "." + mNetworkAgentInfo.network.netId;
+ mEvaluationTimer.reset();
+ final String cmdName = ACTION_LINGER_EXPIRED + "." + mNetId;
mWakeupMessage = makeWakeupMessage(mContext, getHandler(), cmdName, CMD_LINGER_EXPIRED);
long wakeupTime = SystemClock.elapsedRealtime() + mLingerDelayMs;
mWakeupMessage.schedule(wakeupTime);
@@ -663,6 +682,7 @@
HttpURLConnection urlConnection = null;
int httpResponseCode = 599;
String redirectUrl = null;
+ final Stopwatch probeTimer = new Stopwatch().start();
try {
URL url = new URL(getCaptivePortalServerUrl(mContext));
// On networks with a PAC instead of fetching a URL that should result in a 204
@@ -759,6 +779,7 @@
urlConnection.disconnect();
}
}
+ NetworkMonitorEvent.logPortalProbeEvent(mNetId, probeTimer.stop(), httpResponseCode);
return new CaptivePortalProbeResult(httpResponseCode, redirectUrl);
}
diff --git a/services/core/java/com/android/server/fingerprint/ClientMonitor.java b/services/core/java/com/android/server/fingerprint/ClientMonitor.java
index 45b6d3e..8163b79 100644
--- a/services/core/java/com/android/server/fingerprint/ClientMonitor.java
+++ b/services/core/java/com/android/server/fingerprint/ClientMonitor.java
@@ -38,7 +38,7 @@
protected static final boolean DEBUG = FingerprintService.DEBUG;
private IBinder mToken;
private IFingerprintServiceReceiver mReceiver;
- private int mCallingUserId;
+ private int mTargetUserId;
private int mGroupId;
private boolean mIsRestricted; // True if client does not have MANAGE_FINGERPRINT permission
private String mOwner;
@@ -50,20 +50,20 @@
* @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 callingUserId user id of calling user
+ * @param userId target user id for operation
* @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 callingUserId, int groupId,boolean restricted,
+ IFingerprintServiceReceiver receiver, int userId, int groupId,boolean restricted,
String owner) {
mContext = context;
mHalDeviceId = halDeviceId;
mToken = token;
mReceiver = receiver;
- mCallingUserId = callingUserId;
+ mTargetUserId = userId;
mGroupId = groupId;
mIsRestricted = restricted;
mOwner = owner;
@@ -197,8 +197,8 @@
return mIsRestricted;
}
- public final int getCallingUserId() {
- return mCallingUserId;
+ public final int getTargetUserId() {
+ return mTargetUserId;
}
public final int getGroupId() {
diff --git a/services/core/java/com/android/server/fingerprint/EnumerateClient.java b/services/core/java/com/android/server/fingerprint/EnumerateClient.java
index e826fee..52dbd5d 100644
--- a/services/core/java/com/android/server/fingerprint/EnumerateClient.java
+++ b/services/core/java/com/android/server/fingerprint/EnumerateClient.java
@@ -41,7 +41,7 @@
try {
final int result = daemon.enumerate();
if (result != 0) {
- Slog.w(TAG, "start enumerate for user " + getCallingUserId()
+ Slog.w(TAG, "start enumerate for user " + getTargetUserId()
+ " failed, result=" + result);
onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
return result;
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index fcf7bf5..9a2db8e 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -356,7 +356,7 @@
}
}
- void startRemove(IBinder token, int fingerId, int callingUserId, int groupId,
+ void startRemove(IBinder token, int fingerId, int groupId, int userId,
IFingerprintServiceReceiver receiver, boolean restricted) {
IFingerprintDaemon daemon = getFingerprintDaemon();
if (daemon == null) {
@@ -364,7 +364,7 @@
return;
}
RemovalClient client = new RemovalClient(getContext(), mHalDeviceId, token,
- receiver, callingUserId, groupId, fingerId, restricted, token.toString()) {
+ receiver, fingerId, groupId, userId, restricted, token.toString()) {
@Override
public void notifyUserActivity() {
FingerprintService.this.userActivity();
@@ -794,14 +794,13 @@
@Override // Binder call
public void remove(final IBinder token, final int fingerId, final int groupId,
- final IFingerprintServiceReceiver receiver) {
+ final int userId, final IFingerprintServiceReceiver receiver) {
checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission
final boolean restricted = isRestricted();
- final int callingUserId = UserHandle.getCallingUserId();
mHandler.post(new Runnable() {
@Override
public void run() {
- startRemove(token, fingerId, callingUserId, groupId, receiver, restricted);
+ startRemove(token, fingerId, groupId, userId, receiver, restricted);
}
});
diff --git a/services/core/java/com/android/server/fingerprint/RemovalClient.java b/services/core/java/com/android/server/fingerprint/RemovalClient.java
index ffa3c3f..bcf2264 100644
--- a/services/core/java/com/android/server/fingerprint/RemovalClient.java
+++ b/services/core/java/com/android/server/fingerprint/RemovalClient.java
@@ -30,14 +30,12 @@
*/
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,
+ IFingerprintServiceReceiver receiver, int fingerId, int groupId, int userId,
boolean restricted, String owner) {
super(context, halDeviceId, token, receiver, userId, groupId, restricted, owner);
mFingerId = fingerId;
- mUserIdForRemove = userId;
}
@Override
@@ -72,25 +70,21 @@
*/
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;
+ if (receiver != null) {
+ receiver.onRemoved(getHalDeviceId(), fingerId, groupId);
+ }
} catch (RemoteException e) {
Slog.w(TAG, "Failed to notify Removed:", e);
}
- return false;
+ return fingerId == 0;
}
@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;
+ getTargetUserId());
}
return sendRemoved(fingerId, getGroupId());
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index c7c765bb..c649012 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -1349,8 +1349,8 @@
if (keyboardLayoutDescriptor == null) {
throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
}
- if (imeInfo == null || imeSubtype == null) {
- throw new IllegalArgumentException("imeInfo and imeSubtype must not be null");
+ if (imeInfo == null) {
+ throw new IllegalArgumentException("imeInfo must not be null");
}
InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(imeInfo, imeSubtype);
setKeyboardLayoutForInputDeviceInner(identifier, handle, keyboardLayoutDescriptor);
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index 5953dde..07048a4 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -17,16 +17,16 @@
package com.android.server.lights;
import com.android.server.SystemService;
-import com.android.server.vr.VrManagerInternal;
import com.android.server.vr.VrManagerService;
-import com.android.server.vr.VrStateListener;
+import android.app.ActivityManager;
import android.content.Context;
import android.os.Handler;
-import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.os.Trace;
+import android.os.UserHandle;
+import android.provider.Settings;
import android.service.vr.IVrManager;
import android.service.vr.IVrStateCallbacks;
import android.util.Slog;
@@ -36,6 +36,7 @@
static final boolean DEBUG = false;
final LightImpl mLights[] = new LightImpl[LightsManager.LIGHT_ID_COUNT];
+ private boolean mVrModeEnabled;
private final class LightImpl extends Light {
@@ -179,17 +180,34 @@
}
}
+ private int getVrDisplayMode() {
+ int currentUser = ActivityManager.getCurrentUser();
+ return Settings.Secure.getIntForUser(getContext().getContentResolver(),
+ Settings.Secure.VR_DISPLAY_MODE,
+ /*default*/Settings.Secure.VR_DISPLAY_MODE_LOW_PERSISTENCE,
+ currentUser);
+ }
+
private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
@Override
public void onVrStateChanged(boolean enabled) throws RemoteException {
LightImpl l = mLights[LightsManager.LIGHT_ID_BACKLIGHT];
- if (enabled) {
- if (DEBUG) Slog.v(TAG, "VR mode enabled, setting brightness to low persistence");
- l.enableLowPersistence();
+ int vrDisplayMode = getVrDisplayMode();
+ // User leaves VR mode before altering display settings.
+ if (enabled && vrDisplayMode == Settings.Secure.VR_DISPLAY_MODE_LOW_PERSISTENCE) {
+ if (!mVrModeEnabled) {
+ if (DEBUG)
+ Slog.v(TAG, "VR mode enabled, setting brightness to low persistence");
+ l.enableLowPersistence();
+ mVrModeEnabled = true;
+ }
} else {
- if (DEBUG) Slog.v(TAG, "VR mode disabled, resetting brightnes");
- l.disableLowPersistence();
+ if (mVrModeEnabled) {
+ if (DEBUG) Slog.v(TAG, "VR mode disabled, resetting brightnes");
+ l.disableLowPersistence();
+ mVrModeEnabled = false;
+ }
}
}
};
diff --git a/services/core/java/com/android/server/notification/CalendarTracker.java b/services/core/java/com/android/server/notification/CalendarTracker.java
index 783b16f..5d50f3b 100644
--- a/services/core/java/com/android/server/notification/CalendarTracker.java
+++ b/services/core/java/com/android/server/notification/CalendarTracker.java
@@ -43,14 +43,15 @@
private static final int EVENT_CHECK_LOOKAHEAD = 24 * 60 * 60 * 1000;
private static final String[] INSTANCE_PROJECTION = {
- Instances.BEGIN,
- Instances.END,
- Instances.TITLE,
- Instances.VISIBLE,
- Instances.EVENT_ID,
- Instances.OWNER_ACCOUNT,
- Instances.CALENDAR_ID,
- Instances.AVAILABILITY,
+ Instances.BEGIN,
+ Instances.END,
+ Instances.TITLE,
+ Instances.VISIBLE,
+ Instances.EVENT_ID,
+ Instances.CALENDAR_DISPLAY_NAME,
+ Instances.OWNER_ACCOUNT,
+ Instances.CALENDAR_ID,
+ Instances.AVAILABILITY,
};
private static final String INSTANCE_ORDER_BY = Instances.BEGIN + " ASC";
@@ -87,49 +88,6 @@
pw.print(prefix); pw.print("u="); pw.println(mUserContext.getUserId());
}
- public void dumpContent(Uri uri) {
- Log.d(TAG, "dumpContent: " + uri);
- final Cursor cursor = mUserContext.getContentResolver().query(uri, null, null, null, null);
- try {
- int r = 0;
- while (cursor.moveToNext()) {
- Log.d(TAG, "Row " + (++r) + ": id="
- + cursor.getInt(cursor.getColumnIndex(BaseColumns._ID)));
- for (int i = 0; i < cursor.getColumnCount(); i++) {
- final String name = cursor.getColumnName(i);
- final int type = cursor.getType(i);
- Object o = null;
- String typeName = null;
- switch (type) {
- case Cursor.FIELD_TYPE_INTEGER:
- o = cursor.getLong(i);
- typeName = "INTEGER";
- break;
- case Cursor.FIELD_TYPE_STRING:
- o = cursor.getString(i);
- typeName = "STRING";
- break;
- case Cursor.FIELD_TYPE_NULL:
- o = null;
- typeName = "NULL";
- break;
- default:
- throw new UnsupportedOperationException("type: " + type);
- }
- if (name.equals(BaseColumns._ID)
- || name.toLowerCase().contains("sync")
- || o == null) {
- continue;
- }
- Log.d(TAG, " " + name + "(" + typeName + ")=" + o);
- }
- }
- Log.d(TAG, " " + uri + " " + r + " rows");
- } finally {
- cursor.close();
- }
- }
-
private ArraySet<Long> getPrimaryCalendars() {
final long start = System.currentTimeMillis();
final ArraySet<Long> rt = new ArraySet<>();
@@ -170,18 +128,21 @@
final String title = cursor.getString(2);
final boolean calendarVisible = cursor.getInt(3) == 1;
final int eventId = cursor.getInt(4);
- final String owner = cursor.getString(5);
- final long calendarId = cursor.getLong(6);
- final int availability = cursor.getInt(7);
+ final String name = cursor.getString(5);
+ final String owner = cursor.getString(6);
+ final long calendarId = cursor.getLong(7);
+ final int availability = cursor.getInt(8);
final boolean calendarPrimary = primaryCalendars.contains(calendarId);
- if (DEBUG) Log.d(TAG, String.format("%s %s-%s v=%s a=%s eid=%s o=%s cid=%s p=%s",
+ if (DEBUG) Log.d(TAG, String.format(
+ "%s %s-%s v=%s a=%s eid=%s n=%s o=%s cid=%s p=%s",
title,
new Date(begin), new Date(end), calendarVisible,
- availabilityToString(availability), eventId, owner, calendarId,
+ availabilityToString(availability), eventId, name, owner, calendarId,
calendarPrimary));
final boolean meetsTime = time >= begin && time < end;
final boolean meetsCalendar = calendarVisible && calendarPrimary
- && (filter.calendar == null || Objects.equals(filter.calendar, owner));
+ && (filter.calendar == null || Objects.equals(filter.calendar, owner)
+ || Objects.equals(filter.calendar, name));
final boolean meetsAvailability = availability != Instances.AVAILABILITY_FREE;
if (meetsCalendar && meetsAvailability) {
if (DEBUG) Log.d(TAG, " MEETS CALENDAR & AVAILABILITY");
diff --git a/services/core/java/com/android/server/notification/ZenModeConditions.java b/services/core/java/com/android/server/notification/ZenModeConditions.java
index 0945065..86ca97d 100644
--- a/services/core/java/com/android/server/notification/ZenModeConditions.java
+++ b/services/core/java/com/android/server/notification/ZenModeConditions.java
@@ -99,9 +99,7 @@
@Override
public void onServiceAdded(ComponentName component) {
if (DEBUG) Log.d(TAG, "onServiceAdded " + component);
- if (isAutomaticActive(component)) {
- mHelper.setConfigAsync(mHelper.getConfig(), "zmc.onServiceAdded");
- }
+ mHelper.setConfigAsync(mHelper.getConfig(), "zmc.onServiceAdded");
}
@Override
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index eb49e9f..60e00a9 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -643,18 +643,22 @@
dispatchOnPolicyChanged();
}
mConfig = config;
- final String val = Integer.toString(config.hashCode());
- Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
- if (!evaluateZenMode(reason, setRingerMode)) {
- applyRestrictions(); // evaluateZenMode will also apply restrictions if changed
- }
- mConditions.evaluateConfig(config, true /*processSubscriptions*/);
+ mHandler.postApplyConfig(config, reason, setRingerMode);
return true;
} finally {
Binder.restoreCallingIdentity(identity);
}
}
+ private void applyConfig(ZenModeConfig config, String reason, boolean setRingerMode) {
+ final String val = Integer.toString(config.hashCode());
+ Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
+ if (!evaluateZenMode(reason, setRingerMode)) {
+ applyRestrictions(); // evaluateZenMode will also apply restrictions if changed
+ }
+ mConditions.evaluateConfig(config, true /*processSubscriptions*/);
+ }
+
private int getZenModeSetting() {
return Global.getInt(mContext.getContentResolver(), Global.ZEN_MODE, Global.ZEN_MODE_OFF);
}
@@ -1071,14 +1075,23 @@
private static final int MSG_DISPATCH = 1;
private static final int MSG_METRICS = 2;
private static final int MSG_SET_CONFIG = 3;
+ private static final int MSG_APPLY_CONFIG = 4;
private final class ConfigMessageData {
public final ZenModeConfig config;
public final String reason;
+ public final boolean setRingerMode;
ConfigMessageData(ZenModeConfig config, String reason) {
this.config = config;
this.reason = reason;
+ this.setRingerMode = false;
+ }
+
+ ConfigMessageData(ZenModeConfig config, String reason, boolean setRingerMode) {
+ this.config = config;
+ this.reason = reason;
+ this.setRingerMode = setRingerMode;
}
}
@@ -1102,6 +1115,11 @@
sendMessage(obtainMessage(MSG_SET_CONFIG, new ConfigMessageData(config, reason)));
}
+ private void postApplyConfig(ZenModeConfig config, String reason, boolean setRingerMode) {
+ sendMessage(obtainMessage(MSG_APPLY_CONFIG,
+ new ConfigMessageData(config, reason, setRingerMode)));
+ }
+
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
@@ -1112,11 +1130,15 @@
mMetrics.emit();
break;
case MSG_SET_CONFIG:
- ConfigMessageData configData = (ConfigMessageData)msg.obj;
+ ConfigMessageData configData = (ConfigMessageData) msg.obj;
synchronized (mConfig) {
setConfigLocked(configData.config, configData.reason);
}
break;
+ case MSG_APPLY_CONFIG:
+ ConfigMessageData applyConfigData = (ConfigMessageData) msg.obj;
+ applyConfig(applyConfigData.config, applyConfigData.reason,
+ applyConfigData.setRingerMode);
}
}
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 8cd536d..12a2d2e 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -143,7 +143,6 @@
private static final int WAKE_LOCK_STAY_AWAKE = 1 << 5; // only set if already awake
private static final int WAKE_LOCK_DOZE = 1 << 6;
private static final int WAKE_LOCK_DRAW = 1 << 7;
- private static final int WAKE_LOCK_SUSTAINED_PERFORMANCE = 1 << 8;
// Summarizes the user activity state.
private static final int USER_ACTIVITY_SCREEN_BRIGHT = 1 << 0;
@@ -162,7 +161,6 @@
// Power hints defined in hardware/libhardware/include/hardware/power.h.
private static final int POWER_HINT_LOW_POWER = 5;
- private static final int POWER_HINT_SUSTAINED_PERFORMANCE = 6;
private static final int POWER_HINT_VR_MODE = 7;
// Power features defined in hardware/libhardware/include/hardware/power.h.
@@ -470,9 +468,6 @@
// True if we are currently in light device idle mode.
private boolean mLightDeviceIdleMode;
- // True if we are currently in sustained performance mode.
- private boolean mSustainedPerformanceMode;
-
// Set of app ids that we will always respect the wake locks for.
int[] mDeviceIdleWhitelist = new int[0];
@@ -481,8 +476,6 @@
private final SparseIntArray mUidState = new SparseIntArray();
- private final SparseIntArray mSustainedPerformanceUid = new SparseIntArray();
-
// True if theater mode is enabled
private boolean mTheaterModeEnabled;
@@ -879,12 +872,6 @@
throw new IllegalArgumentException("Wake lock is already dead.");
}
mWakeLocks.add(wakeLock);
-
- if ((flags & PowerManager.WAKE_LOCK_LEVEL_MASK)
- == PowerManager.SUSTAINED_PERFORMANCE_WAKE_LOCK) {
- int numberWakelock = mSustainedPerformanceUid.get(uid);
- mSustainedPerformanceUid.put(uid, numberWakelock + 1);
- }
setWakeLockDisabledStateLocked(wakeLock);
notifyAcquire = true;
}
@@ -953,17 +940,6 @@
mRequestWaitForNegativeProximity = true;
}
-
- if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
- == PowerManager.SUSTAINED_PERFORMANCE_WAKE_LOCK) {
- int numberWakelock = mSustainedPerformanceUid.get(wakeLock.mOwnerUid);
- if (numberWakelock == 1) {
- mSustainedPerformanceUid.delete(wakeLock.mOwnerUid);
- } else {
- mSustainedPerformanceUid.put(wakeLock.mOwnerUid, numberWakelock - 1);
- }
- }
-
wakeLock.mLock.unlinkToDeath(wakeLock, 0);
removeWakeLockLocked(wakeLock, index);
}
@@ -1586,10 +1562,6 @@
break;
case PowerManager.DRAW_WAKE_LOCK:
mWakeLockSummary |= WAKE_LOCK_DRAW;
- case PowerManager.SUSTAINED_PERFORMANCE_WAKE_LOCK:
- if (!wakeLock.mDisabled) {
- mWakeLockSummary |= WAKE_LOCK_SUSTAINED_PERFORMANCE;
- }
break;
}
}
@@ -2288,14 +2260,6 @@
if (autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) {
setHalAutoSuspendModeLocked(true);
}
-
- if (mSustainedPerformanceMode
- && (mWakeLockSummary & WAKE_LOCK_SUSTAINED_PERFORMANCE) == 0) {
- setSustainedPerformanceModeLocked(false);
- } else if (!mSustainedPerformanceMode
- && (mWakeLockSummary & WAKE_LOCK_SUSTAINED_PERFORMANCE) != 0) {
- setSustainedPerformanceModeLocked(true);
- }
}
/**
@@ -2394,12 +2358,6 @@
}
}
- private void setSustainedPerformanceModeLocked(boolean mode) {
- mSustainedPerformanceMode = mode;
- powerHintInternal(POWER_HINT_SUSTAINED_PERFORMANCE,
- mSustainedPerformanceMode ? 1 : 0);
- }
-
boolean isDeviceIdleModeInternal() {
synchronized (mLock) {
return mDeviceIdleMode;
@@ -2531,7 +2489,7 @@
void updateUidProcStateInternal(int uid, int procState) {
synchronized (mLock) {
mUidState.put(uid, procState);
- if (mDeviceIdleMode || mSustainedPerformanceUid.get(uid) != 0) {
+ if (mDeviceIdleMode) {
updateWakeLockDisabledStatesLocked();
}
}
@@ -2552,9 +2510,7 @@
for (int i = 0; i < numWakeLocks; i++) {
final WakeLock wakeLock = mWakeLocks.get(i);
if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
- == PowerManager.PARTIAL_WAKE_LOCK
- || (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
- == PowerManager.SUSTAINED_PERFORMANCE_WAKE_LOCK) {
+ == PowerManager.PARTIAL_WAKE_LOCK) {
if (setWakeLockDisabledStateLocked(wakeLock)) {
changed = true;
if (wakeLock.mDisabled) {
@@ -2573,9 +2529,9 @@
}
private boolean setWakeLockDisabledStateLocked(WakeLock wakeLock) {
- boolean disabled = false;
if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
== PowerManager.PARTIAL_WAKE_LOCK) {
+ boolean disabled = false;
if (mDeviceIdleMode) {
final int appid = UserHandle.getAppId(wakeLock.mOwnerUid);
// If we are in idle mode, we will ignore all partial wake locks that are
@@ -2589,16 +2545,10 @@
disabled = true;
}
}
- } else if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
- == PowerManager.SUSTAINED_PERFORMANCE_WAKE_LOCK
- && mUidState.get(wakeLock.mOwnerUid,
- ActivityManager.PROCESS_STATE_CACHED_EMPTY)
- > ActivityManager.PROCESS_STATE_TOP) {
- disabled = true;
- }
- if (wakeLock.mDisabled != disabled) {
- wakeLock.mDisabled = disabled;
- return true;
+ if (wakeLock.mDisabled != disabled) {
+ wakeLock.mDisabled = disabled;
+ return true;
+ }
}
return false;
}
@@ -2806,7 +2756,6 @@
pw.println(" mBatteryLevelLow=" + mBatteryLevelLow);
pw.println(" mLightDeviceIdleMode=" + mLightDeviceIdleMode);
pw.println(" mDeviceIdleMode=" + mDeviceIdleMode);
- pw.println(" mSustainedPerformanceMode=" + mSustainedPerformanceMode);
pw.println(" mDeviceIdleWhitelist=" + Arrays.toString(mDeviceIdleWhitelist));
pw.println(" mDeviceIdleTempWhitelist=" + Arrays.toString(mDeviceIdleTempWhitelist));
pw.println(" mLastWakeTime=" + TimeUtils.formatUptime(mLastWakeTime));
@@ -2921,14 +2870,6 @@
pw.println();
pw.println("Display Power: " + mDisplayPowerCallbacks);
- pw.println();
- pw.println("Sustained Performance UIDs:");
- for (int i=0; i<mSustainedPerformanceUid.size(); i++) {
- pw.print(" UID "); UserHandle.formatUid(pw, mSustainedPerformanceUid.keyAt(i));
- pw.print(": "); pw.println(mSustainedPerformanceUid.valueAt(i));
- }
-
-
wcd = mWirelessChargerDetector;
}
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 30442bc..e13ee13 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -161,8 +161,10 @@
PackageMonitor monitor = new PackageMonitor() {
private void buildTvInputList(String[] packages) {
synchronized (mLock) {
- buildTvInputListLocked(getChangingUserId(), packages);
- buildTvContentRatingSystemListLocked(getChangingUserId());
+ if (mCurrentUserId == getChangingUserId()) {
+ buildTvInputListLocked(mCurrentUserId, packages);
+ buildTvContentRatingSystemListLocked(mCurrentUserId);
+ }
}
}
diff --git a/services/core/java/com/android/server/vr/EnabledComponentsObserver.java b/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
index 30194bf..249a076 100644
--- a/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
+++ b/services/core/java/com/android/server/vr/EnabledComponentsObserver.java
@@ -212,7 +212,7 @@
if (userManager == null) {
return null;
}
- return userManager.getProfileIdsWithDisabled(ActivityManager.getCurrentUser());
+ return userManager.getEnabledProfileIds(ActivityManager.getCurrentUser());
}
public static ArraySet<ComponentName> loadComponentNames(PackageManager pm, int userId,
diff --git a/services/core/java/com/android/server/vr/SettingsObserver.java b/services/core/java/com/android/server/vr/SettingsObserver.java
index ce76863..3d1227d 100644
--- a/services/core/java/com/android/server/vr/SettingsObserver.java
+++ b/services/core/java/com/android/server/vr/SettingsObserver.java
@@ -38,7 +38,7 @@
public class SettingsObserver {
private final String mSecureSettingName;
- private final BroadcastReceiver mSettingRestorReceiver;
+ private final BroadcastReceiver mSettingRestoreReceiver;
private final ContentObserver mContentObserver;
private final Set<SettingChangeListener> mSettingsListeners = new ArraySet<>();
@@ -67,7 +67,7 @@
@NonNull final Uri settingUri, @NonNull final String secureSettingName) {
mSecureSettingName = secureSettingName;
- mSettingRestorReceiver = new BroadcastReceiver() {
+ mSettingRestoreReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
@@ -117,7 +117,6 @@
*/
public void addListener(@NonNull SettingChangeListener listener) {
mSettingsListeners.add(listener);
-
}
/**
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 91b6914..d6ace91 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -34,7 +34,6 @@
import android.app.WallpaperInfo;
import android.app.WallpaperManager;
import android.app.admin.DevicePolicyManager;
-import android.app.backup.BackupManager;
import android.app.backup.WallpaperBackupHelper;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -61,6 +60,7 @@
import android.os.FileUtils;
import android.os.IBinder;
import android.os.IRemoteCallback;
+import android.os.Process;
import android.os.ParcelFileDescriptor;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
@@ -205,7 +205,8 @@
if (path == null) {
return;
}
- final boolean written = (event == CLOSE_WRITE || event == MOVED_TO);
+ final boolean moved = (event == MOVED_TO);
+ final boolean written = (event == CLOSE_WRITE || moved);
final File changedFile = new File(mWallpaperDir, path);
// System and system+lock changes happen on the system wallpaper input file;
@@ -224,13 +225,6 @@
+ " written=" + written);
}
synchronized (mLock) {
- if (sysWallpaperChanged || mWallpaperInfoFile.equals(changedFile)) {
- // changing the wallpaper means we'll need to back up the new one
- long origId = Binder.clearCallingIdentity();
- BackupManager bm = new BackupManager(mContext);
- bm.dataChanged();
- Binder.restoreCallingIdentity(origId);
- }
if (sysWallpaperChanged || lockWallpaperChanged) {
notifyCallbacksLocked(wallpaper);
if (wallpaper.wallpaperComponent == null
@@ -244,6 +238,14 @@
if (DEBUG) {
Slog.v(TAG, "Wallpaper written; generating crop");
}
+ if (moved) {
+ // This is a restore, so generate the crop using any just-restored new
+ // crop guidelines, making sure to preserve our local dimension hints.
+ if (DEBUG) {
+ Slog.v(TAG, "moved-to, therefore restore; reloading metadata");
+ }
+ loadSettingsLocked(wallpaper.userId, true);
+ }
generateCrop(wallpaper);
if (DEBUG) {
Slog.v(TAG, "Crop done; invoking completion callback");
@@ -491,6 +493,11 @@
IWallpaperManagerCallback setComplete;
/**
+ * Is the OS allowed to back up this wallpaper imagery?
+ */
+ boolean allowBackup;
+
+ /**
* Resource name if using a picture from the wallpaper gallery
*/
String name = "";
@@ -811,7 +818,7 @@
mMonitor = new MyPackageMonitor();
mMonitor.register(context, null, UserHandle.ALL, true);
getWallpaperDir(UserHandle.USER_SYSTEM).mkdirs();
- loadSettingsLocked(UserHandle.USER_SYSTEM);
+ loadSettingsLocked(UserHandle.USER_SYSTEM, false);
}
private static File getWallpaperDir(int userId) {
@@ -1024,7 +1031,7 @@
wallpaper = mWallpaperMap.get(userId);
if (wallpaper == null) {
// Might need to bring it in the first time to establish our rewrite
- loadSettingsLocked(userId);
+ loadSettingsLocked(userId, false);
wallpaper = mWallpaperMap.get(userId);
}
}
@@ -1102,7 +1109,7 @@
WallpaperData wd = mWallpaperMap.get(user.id);
if (wd == null) {
// User hasn't started yet, so load her settings to peek at the wallpaper
- loadSettingsLocked(user.id);
+ loadSettingsLocked(user.id, false);
wd = mWallpaperMap.get(user.id);
}
if (wd != null && name.equals(wd.name)) {
@@ -1235,7 +1242,7 @@
if (wallpaper == null) {
// common case, this is the first lookup post-boot of the system or
// unified lock, so we bring up the saved state lazily now and recheck.
- loadSettingsLocked(wallpaperUserId);
+ loadSettingsLocked(wallpaperUserId, false);
wallpaper = whichSet.get(wallpaperUserId);
if (wallpaper == null) {
return null;
@@ -1304,7 +1311,8 @@
@Override
public ParcelFileDescriptor setWallpaper(String name, String callingPackage,
- Rect cropHint, Bundle extras, int which, IWallpaperManagerCallback completion) {
+ Rect cropHint, boolean allowBackup, Bundle extras, int which,
+ IWallpaperManagerCallback completion) {
checkPermission(android.Manifest.permission.SET_WALLPAPER);
if ((which & (FLAG_LOCK|FLAG_SYSTEM)) == 0) {
@@ -1342,6 +1350,9 @@
wallpaper.whichPending = which;
wallpaper.setComplete = completion;
wallpaper.cropHint.set(cropHint);
+ if ((which & FLAG_SYSTEM) != 0) {
+ wallpaper.allowBackup = allowBackup;
+ }
}
return pfd;
} finally {
@@ -1651,6 +1662,16 @@
return !um.hasUserRestriction(UserManager.DISALLOW_SET_WALLPAPER);
}
+ @Override
+ public boolean isWallpaperBackupEligible(int userId) {
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("Only the system may call isWallpaperBackupEligible");
+ }
+
+ WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
+ return (wallpaper != null) ? wallpaper.allowBackup : false;
+ }
+
private static JournaledFile makeJournaledFile(int userId) {
final String base = new File(getWallpaperDir(userId), WALLPAPER_INFO).getAbsolutePath();
return new JournaledFile(new File(base), new File(base + ".tmp"));
@@ -1721,6 +1742,11 @@
out.attribute(null, "component",
wallpaper.wallpaperComponent.flattenToShortString());
}
+
+ if (wallpaper.allowBackup) {
+ out.attribute(null, "backup", "true");
+ }
+
out.endTag(null, tag);
}
@@ -1764,7 +1790,7 @@
if (wallpaper == null) {
// common case, this is the first lookup post-boot of the system or
// unified lock, so we bring up the saved state lazily now and recheck.
- loadSettingsLocked(userId);
+ loadSettingsLocked(userId, false);
wallpaper = whichSet.get(userId);
// if it's still null here, this is a lock-only operation and there is not
// yet a lock-only wallpaper set for this user, so we need to establish
@@ -1788,7 +1814,7 @@
return wallpaper;
}
- private void loadSettingsLocked(int userId) {
+ private void loadSettingsLocked(int userId, boolean keepDimensionHints) {
if (DEBUG) Slog.v(TAG, "loadSettingsLocked");
JournaledFile journal = makeJournaledFile(userId);
@@ -1801,6 +1827,7 @@
WallpaperData wallpaper = mWallpaperMap.get(userId);
if (wallpaper == null) {
wallpaper = new WallpaperData(userId, WALLPAPER, WALLPAPER_CROP);
+ wallpaper.allowBackup = true;
mWallpaperMap.put(userId, wallpaper);
if (!wallpaper.cropExists()) {
generateCrop(wallpaper);
@@ -1819,7 +1846,7 @@
String tag = parser.getName();
if ("wp".equals(tag)) {
// Common to system + lock wallpapers
- parseWallpaperAttributes(parser, wallpaper);
+ parseWallpaperAttributes(parser, wallpaper, keepDimensionHints);
// A system wallpaper might also be a live wallpaper
String comp = parser.getAttributeValue(null, "component");
@@ -1848,7 +1875,7 @@
WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
mLockWallpaperMap.put(userId, lockWallpaper);
}
- parseWallpaperAttributes(parser, lockWallpaper);
+ parseWallpaperAttributes(parser, lockWallpaper, false);
}
}
} while (type != XmlPullParser.END_DOCUMENT);
@@ -1909,7 +1936,8 @@
}
}
- private void parseWallpaperAttributes(XmlPullParser parser, WallpaperData wallpaper) {
+ private void parseWallpaperAttributes(XmlPullParser parser, WallpaperData wallpaper,
+ boolean keepDimensionHints) {
final String idString = parser.getAttributeValue(null, "id");
if (idString != null) {
final int id = wallpaper.wallpaperId = Integer.parseInt(idString);
@@ -1920,9 +1948,11 @@
wallpaper.wallpaperId = makeWallpaperIdLocked();
}
- wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width"));
- wallpaper.height = Integer.parseInt(parser
- .getAttributeValue(null, "height"));
+ if (!keepDimensionHints) {
+ wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width"));
+ wallpaper.height = Integer.parseInt(parser
+ .getAttributeValue(null, "height"));
+ }
wallpaper.cropHint.left = getAttributeInt(parser, "cropLeft", 0);
wallpaper.cropHint.top = getAttributeInt(parser, "cropTop", 0);
wallpaper.cropHint.right = getAttributeInt(parser, "cropRight", 0);
@@ -1932,6 +1962,7 @@
wallpaper.padding.right = getAttributeInt(parser, "paddingRight", 0);
wallpaper.padding.bottom = getAttributeInt(parser, "paddingBottom", 0);
wallpaper.name = parser.getAttributeValue(null, "name");
+ wallpaper.allowBackup = "true".equals(parser.getAttributeValue(null, "backup"));
}
private int getMaximumSizeDimension() {
@@ -1952,9 +1983,10 @@
WallpaperData wallpaper = null;
boolean success = false;
synchronized (mLock) {
- loadSettingsLocked(UserHandle.USER_SYSTEM);
+ loadSettingsLocked(UserHandle.USER_SYSTEM, false);
wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM);
wallpaper.wallpaperId = makeWallpaperIdLocked(); // always bump id at restore
+ wallpaper.allowBackup = true; // by definition if it was restored
if (wallpaper.nextWallpaperComponent != null
&& !wallpaper.nextWallpaperComponent.equals(mImageWallpaper)) {
if (!bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index eacdd81..1f44b29 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -129,15 +129,19 @@
public void onAnimationStart(Animator animation) {
if (DEBUG) Slog.d(TAG, "onAnimationStart: mTarget=" + mTarget
+ " mReplacement=" + mReplacement);
+ // Ensure that we have prepared the target for animation before
+ // we trigger any size changes, so it can swap surfaces
+ // in to appropriate modes, or do as it wishes otherwise.
if (!mReplacement) {
mTarget.onAnimationStart();
}
- // Ensure that we have prepared the target for animation before
- // we trigger any size changes, so it can swap surfaces
- // in to appropriate modes, or do as it wishes otherwise.
+ // Immediately update the task bounds if they have to become larger, but preserve
+ // the starting position so we don't jump at the beginning of the animation.
if (animatingToLargerSize()) {
- mTarget.setPinnedStackSize(mFrom, mTo);
+ mTmpRect.set(mFrom.left, mFrom.top,
+ mFrom.left + mFrozenTaskWidth, mFrom.top + mFrozenTaskHeight);
+ mTarget.setPinnedStackSize(mFrom, mTmpRect);
}
}
@@ -145,11 +149,15 @@
public void onAnimationEnd(Animator animation) {
if (DEBUG) Slog.d(TAG, "onAnimationEnd: mTarget=" + mTarget
+ " mMoveToFullScreen=" + mMoveToFullScreen + " mWillReplace=" + mWillReplace);
-
- finishAnimation();
if (mMoveToFullScreen && !mWillReplace) {
mTarget.moveToFullscreen();
}
+
+ // If we finish the animation before we move the target to fullscreen,
+ // recents may close itself and we may try and resume the previous
+ // fullscreen app leading to churn and flicker after we then move
+ // our target to fullscreen.
+ finishAnimation();
}
@Override
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index b90d0d1..8a003de 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -116,6 +116,11 @@
private boolean mAnimatingForIme;
private boolean mAdjustedForIme;
private WindowState mDelayedImeWin;
+ private boolean mAdjustedForDivider;
+ private float mDividerAnimationStart;
+ private float mDividerAnimationTarget;
+ private float mLastAnimationProgress;
+ private float mLastDividerProgress;
DockedStackDividerController(WindowManagerService service, DisplayContent displayContent) {
mService = service;
@@ -208,16 +213,18 @@
return mLastVisibility;
}
- void setAdjustedForIme(boolean adjusted, boolean animate, WindowState imeWin) {
- if (mAdjustedForIme != adjusted) {
- mAdjustedForIme = adjusted;
+ void setAdjustedForIme(
+ boolean adjustedForIme, boolean adjustedForDivider,
+ boolean animate, WindowState imeWin) {
+ if (mAdjustedForIme != adjustedForIme || mAdjustedForDivider != adjustedForDivider) {
if (animate) {
- startImeAdjustAnimation(adjusted, imeWin);
+ startImeAdjustAnimation(adjustedForIme, adjustedForDivider, imeWin);
} else {
-
// Animation might be delayed, so only notify if we don't run an animation.
- notifyAdjustedForImeChanged(adjusted, 0 /* duration */);
+ notifyAdjustedForImeChanged(adjustedForIme || adjustedForDivider, 0 /* duration */);
}
+ mAdjustedForIme = adjustedForIme;
+ mAdjustedForDivider = adjustedForDivider;
}
}
@@ -457,11 +464,25 @@
mAnimationTarget = to;
}
- private void startImeAdjustAnimation(boolean adjusted, WindowState imeWin) {
+ private void startImeAdjustAnimation(
+ boolean adjustedForIme, boolean adjustedForDivider, WindowState imeWin) {
mAnimatingForIme = true;
mAnimationStarted = false;
- mAnimationStart = adjusted ? 0 : 1;
- mAnimationTarget = adjusted ? 1 : 0;
+
+ // If we're not in an animation, the starting point depends on whether we're adjusted
+ // or not. If we're already in an animation, we start from where the current animation
+ // left off, so that the motion doesn't look discontinuous.
+ if (!mAnimatingForIme) {
+ mAnimationStart = mAdjustedForIme ? 1 : 0;
+ mDividerAnimationStart = mAdjustedForDivider ? 1 : 0;
+ mLastAnimationProgress = mAnimationStart;
+ mLastDividerProgress = mDividerAnimationStart;
+ } else {
+ mAnimationStart = mLastAnimationProgress;
+ mDividerAnimationStart = mLastDividerProgress;
+ }
+ mAnimationTarget = adjustedForIme ? 1 : 0;
+ mDividerAnimationTarget = adjustedForDivider ? 1 : 0;
final ArrayList<TaskStack> stacks = mDisplayContent.getStacks();
for (int i = stacks.size() - 1; i >= 0; --i) {
@@ -492,10 +513,12 @@
if (mDelayedImeWin != null) {
mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
}
- notifyAdjustedForImeChanged(adjusted, IME_ADJUST_ANIM_DURATION);
+ notifyAdjustedForImeChanged(
+ adjustedForIme || adjustedForDivider, IME_ADJUST_ANIM_DURATION);
};
} else {
- notifyAdjustedForImeChanged(adjusted, IME_ADJUST_ANIM_DURATION);
+ notifyAdjustedForImeChanged(
+ adjustedForIme || adjustedForDivider, IME_ADJUST_ANIM_DURATION);
}
}
@@ -539,11 +562,15 @@
for (int i = stacks.size() - 1; i >= 0; --i) {
final TaskStack stack = stacks.get(i);
if (stack != null && stack.isAdjustedForIme()) {
- if (t >= 1f && mAnimationTarget == 0f) {
+ if (t >= 1f && mAnimationTarget == 0f && mDividerAnimationTarget == 0f) {
stack.resetAdjustedForIme(true /* adjustBoundsNow */);
updated = true;
} else {
- updated |= stack.updateAdjustForIme(getInterpolatedAnimationValue(t),
+ mLastAnimationProgress = getInterpolatedAnimationValue(t);
+ mLastDividerProgress = getInterpolatedDividerValue(t);
+ updated |= stack.updateAdjustForIme(
+ mLastAnimationProgress,
+ mLastDividerProgress,
false /* force */);
}
if (t >= 1f) {
@@ -555,6 +582,8 @@
mService.mWindowPlacerLocked.performSurfacePlacement();
}
if (t >= 1.0f) {
+ mLastAnimationProgress = mAnimationTarget;
+ mLastDividerProgress = mDividerAnimationTarget;
mAnimatingForIme = false;
return false;
} else {
@@ -596,6 +625,10 @@
return t * mAnimationTarget + (1 - t) * mAnimationStart;
}
+ private float getInterpolatedDividerValue(float t) {
+ return t * mDividerAnimationTarget + (1 - t) * mDividerAnimationStart;
+ }
+
/**
* Gets the amount how much to minimize a stack depending on the interpolated fraction t.
*/
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 1fd2b1f..a289855 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -126,6 +126,7 @@
private WindowState mImeWin;
private float mMinimizeAmount;
private float mAdjustImeAmount;
+ private float mAdjustDividerAmount;
private final int mDockedStackMinimizeThickness;
// If this is true, we are in the bounds animating mode.
@@ -853,7 +854,8 @@
if (!mAdjustedForIme) {
mAdjustedForIme = true;
mAdjustImeAmount = 0f;
- updateAdjustForIme(0f, true /* force */);
+ mAdjustDividerAmount = 0f;
+ updateAdjustForIme(0f, 0f, true /* force */);
}
}
@@ -873,9 +875,11 @@
*
* @return true if a traversal should be performed after the adjustment.
*/
- boolean updateAdjustForIme(float adjustAmount, boolean force) {
- if (adjustAmount != mAdjustImeAmount || force) {
+ boolean updateAdjustForIme(float adjustAmount, float adjustDividerAmount, boolean force) {
+ if (adjustAmount != mAdjustImeAmount
+ || adjustDividerAmount != mAdjustDividerAmount || force) {
mAdjustImeAmount = adjustAmount;
+ mAdjustDividerAmount = adjustDividerAmount;
updateAdjustedBounds();
return isVisibleForUserLocked();
} else {
@@ -895,6 +899,7 @@
mAdjustedForIme = false;
mImeGoingAway = false;
mAdjustImeAmount = 0f;
+ mAdjustDividerAmount = 0f;
updateAdjustedBounds();
mService.setResizeDimLayer(false, mStackId, 1.0f);
} else {
@@ -992,25 +997,27 @@
(int) (mAdjustImeAmount * bottom + (1 - mAdjustImeAmount) * mBounds.bottom);
mFullyAdjustedImeBounds.set(mBounds);
} else {
- final int top;
- final boolean isFocusedStack = mService.getFocusedStackLocked() == this;
- if (isFocusedStack) {
- // If this stack is docked on bottom and has focus, 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, but only
- // to the extent that leaves at least 30% of the top stack visible.
- final int minTopStackBottom =
- getMinTopStackBottom(displayContentRect, mBounds.top - dividerWidth);
- top = Math.max(
- mBounds.top - yOffset, minTopStackBottom + dividerWidthInactive);
- } else {
- // If this stack is docked on bottom but doesn't have focus, we don't need to adjust
- // for IME, but still need to apply a small adjustment due to the thinner divider.
- top = mBounds.top - dividerWidth + dividerWidthInactive;
- }
+ // When the stack is on bottom and has no focus, it's only adjusted for divider width.
+ final int dividerWidthDelta = dividerWidthInactive - dividerWidth;
+
+ // When the stack is on bottom and has focus, it needs to be moved up so as to
+ // not occluded by IME, and at the same time adjusted for divider width.
+ // We try to move it up by the height of the IME window, but only to the extent
+ // that leaves at least 30% of the top stack visible.
+ // 'top' is where the top of bottom stack will move to in this case.
+ final int topBeforeImeAdjust = mBounds.top - dividerWidth + dividerWidthInactive;
+ final int minTopStackBottom =
+ getMinTopStackBottom(displayContentRect, mBounds.top - dividerWidth);
+ final int top = Math.max(
+ mBounds.top - yOffset, minTopStackBottom + dividerWidthInactive);
mTmpAdjustedBounds.set(mBounds);
- mTmpAdjustedBounds.top =
- (int) (mAdjustImeAmount * top + (1 - mAdjustImeAmount) * mBounds.top);
+ // Account for the adjustment for IME and divider width separately.
+ // (top - topBeforeImeAdjust) is the amount of movement due to IME only,
+ // and dividerWidthDelta is due to divider width change only.
+ mTmpAdjustedBounds.top = mBounds.top +
+ (int) (mAdjustImeAmount * (top - topBeforeImeAdjust) +
+ mAdjustDividerAmount * dividerWidthDelta);
mFullyAdjustedImeBounds.set(mBounds);
mFullyAdjustedImeBounds.top = top;
mFullyAdjustedImeBounds.bottom = top + mBounds.height();
@@ -1082,9 +1089,10 @@
}
setAdjustedBounds(mTmpAdjustedBounds);
- final boolean isFocusedStack = mService.getFocusedStackLocked() == this;
- if (mAdjustedForIme && adjust && !isFocusedStack) {
- final float alpha = mAdjustImeAmount * IME_ADJUST_DIM_AMOUNT;
+ final boolean isImeTarget = (mService.getImeTargetStackLocked() == this);
+ if (mAdjustedForIme && adjust && !isImeTarget) {
+ final float alpha = Math.max(mAdjustImeAmount, mAdjustDividerAmount)
+ * IME_ADJUST_DIM_AMOUNT;
mService.setResizeDimLayer(true, mStackId, alpha);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 38f12a1..aee8fc9 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1805,6 +1805,16 @@
return true;
}
+ private static boolean excludeWindowTypeFromTapOutTask(int windowType) {
+ switch (windowType) {
+ case TYPE_STATUS_BAR:
+ case TYPE_NAVIGATION_BAR:
+ case TYPE_INPUT_METHOD_DIALOG:
+ return true;
+ }
+ return false;
+ }
+
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
@@ -2003,7 +2013,7 @@
res = WindowManagerGlobal.ADD_OKAY;
- if (type == TYPE_STATUS_BAR || type == TYPE_NAVIGATION_BAR) {
+ if (excludeWindowTypeFromTapOutTask(type)) {
displayContent.mTapExcludedWindows.add(win);
}
@@ -2395,7 +2405,7 @@
}
final int type = win.mAttrs.type;
- if (type == TYPE_STATUS_BAR || type == TYPE_NAVIGATION_BAR) {
+ if (excludeWindowTypeFromTapOutTask(type)) {
final DisplayContent displaycontent = win.getDisplayContent();
displaycontent.mTapExcludedWindows.remove(win);
}
@@ -4248,7 +4258,6 @@
WindowManagerPolicy.TRANSIT_EXIT);
}
}
- win.mAnimatingExit = true;
changed = true;
win.setDisplayLayoutNeeded();
}
@@ -7455,27 +7464,38 @@
void adjustForImeIfNeeded(final DisplayContent displayContent) {
final WindowState imeWin = mInputMethodWindow;
- final TaskStack focusedStack = getFocusedStackLocked();
+ final boolean imeVisible = imeWin != null && imeWin.isVisibleLw() && imeWin.isDisplayedLw();
final boolean dockVisible = isStackVisibleLocked(DOCKED_STACK_ID);
- if (imeWin != null && imeWin.isVisibleLw() && imeWin.isDisplayedLw()
- && dockVisible && focusedStack != null) {
- final boolean isFocusOnBottom = focusedStack.getDockSide() == DOCKED_BOTTOM;
+ final TaskStack imeTargetStack = getImeTargetStackLocked();
+
+ // The divider could be adjusted for IME position, or be thinner than usual,
+ // or both. There are three possible cases:
+ // - If IME is visible, and focus is on top, divider is not moved for IME but thinner.
+ // - If IME is visible, and focus is on bottom, divider is moved for IME and thinner.
+ // - If IME is not visible, divider is not moved and is normal width.
+
+ if (imeVisible && dockVisible && imeTargetStack != null) {
+ final boolean isFocusOnBottom = imeTargetStack.getDockSide() == DOCKED_BOTTOM;
final ArrayList<TaskStack> stacks = displayContent.getStacks();
for (int i = stacks.size() - 1; i >= 0; --i) {
final TaskStack stack = stacks.get(i);
final boolean isDockedOnBottom = stack.getDockSide() == DOCKED_BOTTOM;
if (stack.isVisibleLocked() && (isFocusOnBottom || isDockedOnBottom)) {
stack.setAdjustedForIme(imeWin);
+ } else {
+ stack.resetAdjustedForIme(false);
}
}
- displayContent.mDividerControllerLocked.setAdjustedForIme(true, true, imeWin);
+ displayContent.mDividerControllerLocked.setAdjustedForIme(
+ isFocusOnBottom /*ime*/, true /*divider*/, true /*animate*/, 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, imeWin);
+ displayContent.mDividerControllerLocked.setAdjustedForIme(
+ false /*ime*/, false /*divider*/, dockVisible /*animate*/, null);
}
}
@@ -7608,8 +7628,10 @@
return mCurrentFocus;
}
- TaskStack getFocusedStackLocked() {
- return mCurrentFocus != null ? mCurrentFocus.getStack() : null;
+ TaskStack getImeTargetStackLocked() {
+ // Don't use WindowState.getStack() because it returns home stack for system windows.
+ Task imeTask = mInputMethodTarget != null ? mInputMethodTarget.getTask() : null;
+ return imeTask != null ? imeTask.mStack : null;
}
private void showAuditSafeModeNotification() {
@@ -9354,7 +9376,6 @@
WindowState newFocus = computeFocusedWindowLocked();
if (mCurrentFocus != newFocus) {
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
- TaskStack oldFocusedStack = getFocusedStackLocked();
// This check makes sure that we don't already have the focus
// change message pending.
mH.removeMessages(H.REPORT_FOCUS_CHANGE);
@@ -9376,7 +9397,6 @@
mLosingFocus.remove(newFocus);
int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus);
- TaskStack newFocusedStack = getFocusedStackLocked();
if (imWindowChanged && oldFocus != mInputMethodWindow) {
// Focus of the input method window changed. Perform layout if needed.
@@ -9406,18 +9426,6 @@
mInputMonitor.setInputFocusLw(mCurrentFocus, updateInputWindows);
}
- // TODO: Reset and re-apply IME adjustment if needed when stack focus changed.
- // This makes sure divider starts an animation from pre-adjust position to final
- // position. Ideally we want to skip the reset and animation from current position
- // directly to final position.
- final WindowState imeWin = mInputMethodWindow;
- if (oldFocusedStack != null) {
- oldFocusedStack.resetAdjustedForIme(true);
- }
- if (newFocusedStack != null) {
- newFocusedStack.resetAdjustedForIme(true);
- }
- displayContent.mDividerControllerLocked.setAdjustedForIme(false, false, imeWin);
adjustForImeIfNeeded(displayContent);
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 6eed5e7..af47369 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -100,6 +100,8 @@
void hideInTransaction(String reason) {
if (SHOW_TRANSACTIONS) logSurface("HIDE ( " + reason + " )", null);
mHiddenForOtherReasons = true;
+
+ mAnimator.destroyPreservedSurfaceLocked();
updateVisibility();
}
@@ -180,6 +182,7 @@
updateVisibility();
} else {
mHiddenForCrop = true;
+ mAnimator.destroyPreservedSurfaceLocked();
updateVisibility();
}
} catch (RuntimeException e) {
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 1e6c585..928fcc0 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -8,6 +8,7 @@
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
@@ -128,6 +129,9 @@
private boolean mTraversalScheduled;
private int mDeferDepth = 0;
+ private boolean mSustainedPerformanceModeEnabled = false;
+ private boolean mSustainedPerformanceModeCurrent = false;
+
private static final class LayerAndToken {
public int layer;
public AppWindowToken token;
@@ -288,7 +292,7 @@
mButtonBrightness = -1;
mUserActivityTimeout = -1;
mObscureApplicationContentOnSecondaryDisplays = false;
-
+ mSustainedPerformanceModeCurrent = false;
mService.mTransactionSequence++;
final DisplayContent defaultDisplay = mService.getDefaultDisplayContentLocked();
@@ -487,6 +491,13 @@
mUserActivityTimeout);
}
+ if (mSustainedPerformanceModeCurrent != mSustainedPerformanceModeEnabled) {
+ mSustainedPerformanceModeEnabled = mSustainedPerformanceModeCurrent;
+ mService.mPowerManagerInternal.powerHint(
+ mService.mPowerManagerInternal.POWER_HINT_SUSTAINED_PERFORMANCE_MODE,
+ (mSustainedPerformanceModeEnabled ? 1 : 0));
+ }
+
if (mService.mTurnOnScreen) {
if (mService.mAllowTheaterModeWakeFromLayout
|| Settings.Global.getInt(mService.mContext.getContentResolver(),
@@ -1409,6 +1420,7 @@
final LayoutParams attrs = w.mAttrs;
final int attrFlags = attrs.flags;
final boolean canBeSeen = w.isDisplayedLw();
+ final int privateflags = attrs.privateFlags;
if (canBeSeen && w.isObscuringFullscreen(dispInfo)) {
// This window completely covers everything behind it,
@@ -1469,6 +1481,9 @@
&& w.mAttrs.preferredDisplayModeId != 0) {
mPreferredModeId = w.mAttrs.preferredDisplayModeId;
}
+ if ((privateflags & PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE) != 0) {
+ mSustainedPerformanceModeCurrent = true;
+ }
}
}
}
diff --git a/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
index 774577d..8ea9bfc 100644
--- a/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
+++ b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
@@ -661,6 +661,16 @@
TranslateToObject(lastLocation, locationObject);
}
+ // sCallbacksObject is created when FlpHardwareProvider on Java side is
+ // initialized. Sometimes the hardware may call this function before the Java
+ // side is ready. In order to prevent the system crash, check whether
+ // sCallbacksObj has been created. If not, simply ignore this event from
+ // hardware.
+ if (sCallbacksObj == NULL) {
+ ALOGE("FlpHardwareProvider hasn't been initialized.");
+ return;
+ }
+
sCallbackEnv->CallVoidMethod(
sCallbacksObj,
sOnGeofenceMonitorStatus,
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 058b631..c5c90e0 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -1194,7 +1194,7 @@
JavaObject object(env, "android/location/GnssMeasurement");
GpsMeasurementFlags flags = measurement->flags;
SET(Svid, static_cast<int32_t>(measurement->prn));
- if (measurement->prn >= 1 || measurement->prn <= 32) {
+ if (measurement->prn >= 1 && measurement->prn <= 32) {
SET(ConstellationType, static_cast<int32_t>(GNSS_CONSTELLATION_GPS));
} else {
ALOGD("Unknown constellation type with Svid = %d.", measurement->prn);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 8c2f559..9f2ca59 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -165,6 +165,10 @@
private static final String UNCRYPT_PACKAGE_FILE = "/cache/recovery/uncrypt_file";
private static final String BLOCK_MAP_FILE = "/cache/recovery/block.map";
+ // maximum number of binder threads used for system_server
+ // will be higher than the system default
+ private static final int sMaxBinderThreads = 31;
+
/**
* Default theme used by the system context. This is used to style
* system-provided dialogs, such as the Power Off dialog, and other
@@ -285,6 +289,9 @@
// Ensure binder calls into the system always run at foreground priority.
BinderInternal.disableBackgroundScheduling(true);
+ // Increase the number of binder threads in system_server
+ BinderInternal.setMaxThreads(sMaxBinderThreads);
+
// Prepare the main looper thread (this thread).
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_FOREGROUND);
diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java
index c8dbe02..27600a7 100644
--- a/services/net/java/android/net/ip/IpReachabilityMonitor.java
+++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java
@@ -24,9 +24,7 @@
import android.net.LinkProperties.ProvisioningChange;
import android.net.ProxyInfo;
import android.net.RouteInfo;
-import android.net.metrics.IpReachabilityMonitorMessageEvent;
-import android.net.metrics.IpReachabilityMonitorProbeEvent;
-import android.net.metrics.IpReachabilityMonitorLostEvent;
+import android.net.metrics.IpReachabilityEvent;
import android.net.netlink.NetlinkConstants;
import android.net.netlink.NetlinkErrorMessage;
import android.net.netlink.NetlinkMessage;
@@ -168,47 +166,54 @@
* Make the kernel perform neighbor reachability detection (IPv4 ARP or IPv6 ND)
* for the given IP address on the specified interface index.
*
- * @return true, if the request was successfully passed to the kernel; false otherwise.
+ * @return 0 if the request was successfully passed to the kernel; otherwise return
+ * a non-zero error code.
*/
- public static boolean probeNeighbor(int ifIndex, InetAddress ip) {
- final long IO_TIMEOUT = 300L;
+ private static int probeNeighbor(int ifIndex, InetAddress ip) {
final String msgSnippet = "probing ip=" + ip.getHostAddress() + "%" + ifIndex;
if (DBG) { Log.d(TAG, msgSnippet); }
final byte[] msg = RtNetlinkNeighborMessage.newNewNeighborMessage(
1, ip, StructNdMsg.NUD_PROBE, ifIndex, null);
- boolean returnValue = false;
+ int errno = -OsConstants.EPROTO;
try (NetlinkSocket nlSocket = new NetlinkSocket(OsConstants.NETLINK_ROUTE)) {
+ final long IO_TIMEOUT = 300L;
nlSocket.connectToKernel();
nlSocket.sendMessage(msg, 0, msg.length, IO_TIMEOUT);
final ByteBuffer bytes = nlSocket.recvMessage(IO_TIMEOUT);
+ // recvMessage() guaranteed to not return null if it did not throw.
final NetlinkMessage response = NetlinkMessage.parse(bytes);
if (response != null && response instanceof NetlinkErrorMessage &&
- (((NetlinkErrorMessage) response).getNlMsgError() != null) &&
- (((NetlinkErrorMessage) response).getNlMsgError().error == 0)) {
- returnValue = true;
- } else {
- String errmsg;
- if (bytes == null) {
- errmsg = "null recvMessage";
- } else if (response == null) {
- bytes.position(0);
- errmsg = "raw bytes: " + NetlinkConstants.hexify(bytes);
- } else {
+ (((NetlinkErrorMessage) response).getNlMsgError() != null)) {
+ errno = ((NetlinkErrorMessage) response).getNlMsgError().error;
+ if (errno != 0) {
// TODO: consider ignoring EINVAL (-22), which appears to be
// normal when probing a neighbor for which the kernel does
// not already have / no longer has a link layer address.
+ Log.e(TAG, "Error " + msgSnippet + ", errmsg=" + response.toString());
+ }
+ } else {
+ String errmsg;
+ if (response == null) {
+ bytes.position(0);
+ errmsg = "raw bytes: " + NetlinkConstants.hexify(bytes);
+ } else {
errmsg = response.toString();
}
Log.e(TAG, "Error " + msgSnippet + ", errmsg=" + errmsg);
}
- } catch (ErrnoException | InterruptedIOException | SocketException e) {
- Log.d(TAG, "Error " + msgSnippet, e);
+ } catch (ErrnoException e) {
+ Log.e(TAG, "Error " + msgSnippet, e);
+ errno = -e.errno;
+ } catch (InterruptedIOException e) {
+ Log.e(TAG, "Error " + msgSnippet, e);
+ errno = -OsConstants.ETIMEDOUT;
+ } catch (SocketException e) {
+ Log.e(TAG, "Error " + msgSnippet, e);
+ errno = -OsConstants.EIO;
}
- IpReachabilityMonitorProbeEvent.logEvent("ifindex-" + ifIndex, ip.getHostAddress(),
- returnValue);
- return returnValue;
+ return errno;
}
public IpReachabilityMonitor(Context context, String ifName, Callback callback)
@@ -354,7 +359,7 @@
}
if (delta == ProvisioningChange.LOST_PROVISIONING) {
- IpReachabilityMonitorLostEvent.logEvent(mInterfaceName);
+ IpReachabilityEvent.logProvisioningLost(mInterfaceName);
final String logMsg = "FAILURE: LOST_PROVISIONING, " + msg;
Log.w(TAG, logMsg);
if (mCallback != null) {
@@ -362,6 +367,8 @@
// an InetAddress argument.
mCallback.notifyLost(ip, logMsg);
}
+ } else {
+ IpReachabilityEvent.logNudFailed(mInterfaceName);
}
}
@@ -385,7 +392,8 @@
if (!stillRunning()) {
break;
}
- probeNeighbor(mInterfaceIndex, target);
+ final int returnValue = probeNeighbor(mInterfaceIndex, target);
+ IpReachabilityEvent.logProbeEvent(mInterfaceName, returnValue);
}
}
@@ -523,8 +531,6 @@
final short msgType = neighMsg.getHeader().nlmsg_type;
final short nudState = ndMsg.ndm_state;
- IpReachabilityMonitorMessageEvent.logEvent(mInterfaceName,
- destination.getHostAddress(), msgType, nudState);
final String eventMsg = "NeighborEvent{"
+ "elapsedMs=" + whenMs + ", "
+ destination.getHostAddress() + ", "
diff --git a/services/net/java/android/net/util/Stopwatch.java b/services/net/java/android/net/util/Stopwatch.java
new file mode 100644
index 0000000..cb15ee5
--- /dev/null
+++ b/services/net/java/android/net/util/Stopwatch.java
@@ -0,0 +1,75 @@
+/*
+ * 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.util;
+
+import android.os.SystemClock;
+
+
+/**
+ * @hide
+ */
+public class Stopwatch {
+ private long mStartTimeMs;
+ private long mStopTimeMs;
+
+ public boolean isStarted() {
+ return (mStartTimeMs > 0);
+ }
+
+ public boolean isStopped() {
+ return (mStopTimeMs > 0);
+ }
+
+ public boolean isRunning() {
+ return (isStarted() && !isStopped());
+ }
+
+ // Returning |this| makes possible the following usage pattern:
+ //
+ // Stopwatch s = new Stopwatch().start();
+ public Stopwatch start() {
+ if (!isStarted()) {
+ mStartTimeMs = SystemClock.elapsedRealtime();
+ }
+ return this;
+ }
+
+ // Returns the total time recorded, in milliseconds, or 0 if not started.
+ public long stop() {
+ if (isRunning()) {
+ mStopTimeMs = SystemClock.elapsedRealtime();
+ }
+ // Return either the delta after having stopped, or 0.
+ return (mStopTimeMs - mStartTimeMs);
+ }
+
+ // Returns the total time recorded to date, in milliseconds.
+ // If the Stopwatch is not running, returns the same value as stop(),
+ // i.e. either the total time recorded before stopping or 0.
+ public long lap() {
+ if (isRunning()) {
+ return (SystemClock.elapsedRealtime() - mStartTimeMs);
+ } else {
+ return stop();
+ }
+ }
+
+ public void reset() {
+ mStartTimeMs = 0;
+ mStopTimeMs = 0;
+ }
+}
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 23f186c..7017d81 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -42,6 +42,7 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
+ <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index 26eed24..4fae4a7 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -74,6 +74,7 @@
import com.android.server.net.NetworkPinner;
import java.net.InetAddress;
+import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
@@ -1788,4 +1789,96 @@
waitFor(cv);
assertPinnedToWifiWithCellDefault();
}
+
+ @SmallTest
+ public void testNetworkRequestMaximum() {
+ final int MAX_REQUESTS = 100;
+ // Test that the limit is enforced when MAX_REQUESTS simultaneous requests are added.
+ NetworkRequest networkRequest = new NetworkRequest.Builder().build();
+ ArrayList<NetworkCallback> networkCallbacks = new ArrayList<NetworkCallback>();
+ try {
+ for (int i = 0; i < MAX_REQUESTS; i++) {
+ NetworkCallback networkCallback = new NetworkCallback();
+ mCm.requestNetwork(networkRequest, networkCallback);
+ networkCallbacks.add(networkCallback);
+ }
+ fail("Registering " + MAX_REQUESTS + " NetworkRequests did not throw exception");
+ } catch (IllegalArgumentException expected) {}
+ for (NetworkCallback networkCallback : networkCallbacks) {
+ mCm.unregisterNetworkCallback(networkCallback);
+ }
+ networkCallbacks.clear();
+
+ try {
+ for (int i = 0; i < MAX_REQUESTS; i++) {
+ NetworkCallback networkCallback = new NetworkCallback();
+ mCm.registerNetworkCallback(networkRequest, networkCallback);
+ networkCallbacks.add(networkCallback);
+ }
+ fail("Registering " + MAX_REQUESTS + " NetworkCallbacks did not throw exception");
+ } catch (IllegalArgumentException expected) {}
+ for (NetworkCallback networkCallback : networkCallbacks) {
+ mCm.unregisterNetworkCallback(networkCallback);
+ }
+ networkCallbacks.clear();
+
+ ArrayList<PendingIntent> pendingIntents = new ArrayList<PendingIntent>();
+ try {
+ for (int i = 0; i < MAX_REQUESTS + 1; i++) {
+ PendingIntent pendingIntent =
+ PendingIntent.getBroadcast(mContext, 0, new Intent("a" + i), 0);
+ mCm.requestNetwork(networkRequest, pendingIntent);
+ pendingIntents.add(pendingIntent);
+ }
+ fail("Registering " + MAX_REQUESTS +
+ " PendingIntent NetworkRequests did not throw exception");
+ } catch (IllegalArgumentException expected) {}
+ for (PendingIntent pendingIntent : pendingIntents) {
+ mCm.unregisterNetworkCallback(pendingIntent);
+ }
+ pendingIntents.clear();
+
+ try {
+ for (int i = 0; i < MAX_REQUESTS + 1; i++) {
+ PendingIntent pendingIntent =
+ PendingIntent.getBroadcast(mContext, 0, new Intent("a" + i), 0);
+ mCm.registerNetworkCallback(networkRequest, pendingIntent);
+ pendingIntents.add(pendingIntent);
+ }
+ fail("Registering " + MAX_REQUESTS +
+ " PendingIntent NetworkCallbacks did not throw exception");
+ } catch (IllegalArgumentException expected) {}
+ for (PendingIntent pendingIntent : pendingIntents) {
+ mCm.unregisterNetworkCallback(pendingIntent);
+ }
+ pendingIntents.clear();
+ mService.waitForIdle(5000);
+
+ // Test that the limit is not hit when MAX_REQUESTS requests are added and removed.
+ for (int i = 0; i < MAX_REQUESTS; i++) {
+ NetworkCallback networkCallback = new NetworkCallback();
+ mCm.requestNetwork(networkRequest, networkCallback);
+ mCm.unregisterNetworkCallback(networkCallback);
+ }
+ mService.waitForIdle();
+ for (int i = 0; i < MAX_REQUESTS; i++) {
+ NetworkCallback networkCallback = new NetworkCallback();
+ mCm.registerNetworkCallback(networkRequest, networkCallback);
+ mCm.unregisterNetworkCallback(networkCallback);
+ }
+ mService.waitForIdle();
+ for (int i = 0; i < MAX_REQUESTS; i++) {
+ PendingIntent pendingIntent =
+ PendingIntent.getBroadcast(mContext, 0, new Intent("b" + i), 0);
+ mCm.requestNetwork(networkRequest, pendingIntent);
+ mCm.unregisterNetworkCallback(pendingIntent);
+ }
+ mService.waitForIdle();
+ for (int i = 0; i < MAX_REQUESTS; i++) {
+ PendingIntent pendingIntent =
+ PendingIntent.getBroadcast(mContext, 0, new Intent("c" + i), 0);
+ mCm.registerNetworkCallback(networkRequest, pendingIntent);
+ mCm.unregisterNetworkCallback(pendingIntent);
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index 4468857..ef9739d 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -32,6 +32,7 @@
import android.content.pm.RegisteredServicesCache.ServiceInfo;
import android.content.pm.RegisteredServicesCacheListener;
import android.content.pm.UserInfo;
+import android.database.Cursor;
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
@@ -64,15 +65,14 @@
Context realTestContext = getContext();
Context mockContext = new MyMockContext(realTestContext);
setContext(mockContext);
- mAms = new MyAccountManagerService(getContext(),
- new MyMockPackageManager(), new MockAccountAuthenticatorCache(), realTestContext);
+ mAms = createAccountManagerService(mockContext, realTestContext);
}
@Override
protected void tearDown() throws Exception {
- new File(mAms.getCeDatabaseName(UserHandle.USER_SYSTEM)).delete();
- new File(mAms.getDeDatabaseName(UserHandle.USER_SYSTEM)).delete();
- new File(mAms.getPreNDatabaseName(UserHandle.USER_SYSTEM)).delete();
+ SQLiteDatabase.deleteDatabase(new File(mAms.getCeDatabaseName(UserHandle.USER_SYSTEM)));
+ SQLiteDatabase.deleteDatabase(new File(mAms.getDeDatabaseName(UserHandle.USER_SYSTEM)));
+ SQLiteDatabase.deleteDatabase(new File(mAms.getPreNDatabaseName(UserHandle.USER_SYSTEM)));
super.tearDown();
}
@@ -88,7 +88,7 @@
}
public void testCheckAddAccount() throws Exception {
- unlockUser(UserHandle.USER_SYSTEM);
+ unlockSystemUser();
Account a11 = new Account("account1", "type1");
Account a21 = new Account("account2", "type1");
Account a31 = new Account("account3", "type1");
@@ -129,7 +129,7 @@
}
public void testPasswords() throws Exception {
- unlockUser(UserHandle.USER_SYSTEM);
+ unlockSystemUser();
Account a11 = new Account("account1", "type1");
Account a12 = new Account("account1", "type2");
mAms.addAccountExplicitly(a11, "p11", null);
@@ -145,7 +145,7 @@
}
public void testUserdata() throws Exception {
- unlockUser(UserHandle.USER_SYSTEM);
+ unlockSystemUser();
Account a11 = new Account("account1", "type1");
Bundle u11 = new Bundle();
u11.putString("a", "a_a11");
@@ -178,7 +178,7 @@
}
public void testAuthtokens() throws Exception {
- unlockUser(UserHandle.USER_SYSTEM);
+ unlockSystemUser();
Account a11 = new Account("account1", "type1");
Account a12 = new Account("account1", "type2");
mAms.addAccountExplicitly(a11, "p11", null);
@@ -211,10 +211,89 @@
assertNull(mAms.peekAuthToken(a12, "att2"));
}
- private void unlockUser(int userId) {
+ public void testRemovedAccountSync() throws Exception {
+ unlockSystemUser();
+ Account a1 = new Account("account1", "type1");
+ Account a2 = new Account("account2", "type2");
+ mAms.addAccountExplicitly(a1, "p1", null);
+ mAms.addAccountExplicitly(a2, "p2", null);
+
+ Context originalContext = ((MyMockContext)getContext()).mTestContext;
+ // create a separate instance of AMS. It initially assumes that user0 is locked
+ AccountManagerService ams2 = createAccountManagerService(getContext(), originalContext);
+
+ // Verify that account can be removed when user is locked
+ ams2.removeAccountInternal(a1);
+ Account[] accounts = ams2.getAccounts(UserHandle.USER_SYSTEM, mContext.getOpPackageName());
+ assertEquals(1, accounts.length);
+ assertEquals("Only a2 should be returned", a2, accounts[0]);
+
+ // Verify that CE db file is unchanged and still has 2 accounts
+ String ceDatabaseName = mAms.getCeDatabaseName(UserHandle.USER_SYSTEM);
+ int accountsNumber = readNumberOfAccountsFromDbFile(originalContext, ceDatabaseName);
+ assertEquals("CE database should still have 2 accounts", 2, accountsNumber);
+
+ // Unlock the user and verify that db has been updated
+ ams2.onUserUnlocked(newIntentForUser(UserHandle.USER_SYSTEM));
+ accountsNumber = readNumberOfAccountsFromDbFile(originalContext, ceDatabaseName);
+ assertEquals("CE database should now have 1 account", 2, accountsNumber);
+ accounts = ams2.getAccounts(UserHandle.USER_SYSTEM, mContext.getOpPackageName());
+ assertEquals(1, accounts.length);
+ assertEquals("Only a2 should be returned", a2, accounts[0]);
+ }
+
+ public void testPreNDatabaseMigration() throws Exception {
+ String preNDatabaseName = mAms.getPreNDatabaseName(UserHandle.USER_SYSTEM);
+ Context originalContext = ((MyMockContext) getContext()).mTestContext;
+ PreNTestDatabaseHelper.createV4Database(originalContext, preNDatabaseName);
+ // Assert that database was created with 1 account
+ int n = readNumberOfAccountsFromDbFile(originalContext, preNDatabaseName);
+ assertEquals("pre-N database should have 1 account", 1, n);
+
+ // Start testing
+ unlockSystemUser();
+ Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName());
+ assertEquals("1 account should be migrated", 1, accounts.length);
+ assertEquals(PreNTestDatabaseHelper.ACCOUNT_NAME, accounts[0].name);
+ assertEquals(PreNTestDatabaseHelper.ACCOUNT_PASSWORD, mAms.getPassword(accounts[0]));
+ assertEquals("Authtoken should be migrated",
+ PreNTestDatabaseHelper.TOKEN_STRING,
+ mAms.peekAuthToken(accounts[0], PreNTestDatabaseHelper.TOKEN_TYPE));
+
+ assertFalse("pre-N database file should be removed but was found at " + preNDatabaseName,
+ new File(preNDatabaseName).exists());
+
+ // Verify that ce/de files are present
+ String deDatabaseName = mAms.getDeDatabaseName(UserHandle.USER_SYSTEM);
+ String ceDatabaseName = mAms.getCeDatabaseName(UserHandle.USER_SYSTEM);
+ assertTrue("DE database file should be created at " + deDatabaseName,
+ new File(deDatabaseName).exists());
+ assertTrue("CE database file should be created at " + ceDatabaseName,
+ new File(ceDatabaseName).exists());
+ }
+
+ private int readNumberOfAccountsFromDbFile(Context context, String dbName) {
+ SQLiteDatabase ceDb = context.openOrCreateDatabase(dbName, 0, null);
+ try (Cursor cursor = ceDb.rawQuery("SELECT count(*) FROM accounts", null)) {
+ assertTrue(cursor.moveToNext());
+ return cursor.getInt(0);
+ }
+ }
+
+ private AccountManagerService createAccountManagerService(Context mockContext,
+ Context realContext) {
+ return new MyAccountManagerService(mockContext,
+ new MyMockPackageManager(), new MockAccountAuthenticatorCache(), realContext);
+ }
+
+ private void unlockSystemUser() {
+ mAms.onUserUnlocked(newIntentForUser(UserHandle.USER_SYSTEM));
+ }
+
+ private static Intent newIntentForUser(int userId) {
Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
- mAms.onUserUnlocked(intent);
+ return intent;
}
static public class MockAccountAuthenticatorCache implements IAccountAuthenticatorCache {
@@ -264,11 +343,13 @@
private Context mTestContext;
private AppOpsManager mAppOpsManager;
private UserManager mUserManager;
+ private PackageManager mPackageManager;
public MyMockContext(Context testContext) {
this.mTestContext = testContext;
this.mAppOpsManager = mock(AppOpsManager.class);
this.mUserManager = mock(UserManager.class);
+ this.mPackageManager = mock(PackageManager.class);
final UserInfo ui = new UserInfo(UserHandle.USER_SYSTEM, "user0", 0);
when(mUserManager.getUserInfo(eq(ui.id))).thenReturn(ui);
}
@@ -279,6 +360,11 @@
}
@Override
+ public PackageManager getPackageManager() {
+ return mPackageManager;
+ }
+
+ @Override
public Object getSystemService(String name) {
if (Context.APP_OPS_SERVICE.equals(name)) {
return mAppOpsManager;
diff --git a/services/tests/servicestests/src/com/android/server/accounts/PreNTestDatabaseHelper.java b/services/tests/servicestests/src/com/android/server/accounts/PreNTestDatabaseHelper.java
new file mode 100644
index 0000000..97adbe6
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accounts/PreNTestDatabaseHelper.java
@@ -0,0 +1,98 @@
+/*
+ * 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.accounts;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+
+/**
+ * Helper class for emulating pre-N database
+ */
+class PreNTestDatabaseHelper extends SQLiteOpenHelper {
+
+ public static final String TOKEN_STRING = "token-string-123";
+ public static final String ACCOUNT_TYPE = "type1";
+ public static final String ACCOUNT_NAME = "account@" + ACCOUNT_TYPE;
+ public static final String ACCOUNT_PASSWORD = "Password";
+ public static final String TOKEN_TYPE = "SID";
+
+ public PreNTestDatabaseHelper(Context context, String name) {
+ super(context, name, null, 4);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE accounts ( "
+ + "_id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ + "name TEXT NOT NULL, "
+ + "type TEXT NOT NULL, "
+ + "password TEXT, "
+ + "UNIQUE(name, type))");
+ db.execSQL("INSERT INTO accounts (name, type, password) VALUES "
+ + "('" + ACCOUNT_NAME + "', '" + ACCOUNT_TYPE + "', '" + ACCOUNT_PASSWORD + "')");
+
+ db.execSQL("CREATE TABLE authtokens ( "
+ + "_id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ + "accounts_id INTEGER NOT NULL, "
+ + "type TEXT NOT NULL, "
+ + "authtoken TEXT, "
+ + "UNIQUE (accounts_id, type ))");
+ db.execSQL("INSERT INTO authtokens (accounts_id, type, authtoken) VALUES "
+ + "(1, '" + TOKEN_TYPE + "', '" + TOKEN_STRING + "')");
+
+ db.execSQL("CREATE TABLE grants ( "
+ + "accounts_id INTEGER NOT NULL, "
+ + "auth_token_type STRING NOT NULL, "
+ + "uid INTEGER NOT NULL, "
+ + "UNIQUE (accounts_id,auth_token_type,uid))");
+
+ db.execSQL("CREATE TABLE extras ( "
+ + "_id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ + "accounts_id INTEGER, "
+ + "key TEXT NOT NULL, "
+ + "value TEXT, "
+ + "UNIQUE(accounts_id , key))");
+
+ db.execSQL("CREATE TABLE meta ( "
+ + "key TEXT PRIMARY KEY NOT NULL, "
+ + "value TEXT)");
+
+ db.execSQL(""
+ + " CREATE TRIGGER accountsDelete DELETE ON accounts "
+ + " BEGIN"
+ + " DELETE FROM authtokens"
+ + " WHERE accounts_id=OLD._id;"
+ + " DELETE FROM extras"
+ + " WHERE accounts_id=OLD._id;"
+ + " DELETE FROM grants"
+ + " WHERE accounts_id=OLD._id;"
+ + " END");
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ throw new UnsupportedOperationException("Upgrade of test database is not supported");
+ }
+
+ public static void createV4Database(Context context, String name) {
+ PreNTestDatabaseHelper helper = new PreNTestDatabaseHelper(context, name);
+ helper.getWritableDatabase();
+ helper.close();
+ }
+
+}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 1e9db18..3f9da4c 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -183,11 +183,11 @@
try {
if (mActiveSession == null || token != mActiveSession.mToken) {
Slog.w(TAG, "startVoiceActivity does not match active session");
- return ActivityManager.START_CANCELED;
+ return ActivityManager.START_VOICE_NOT_ACTIVE_SESSION;
}
if (!mActiveSession.mShown) {
Slog.w(TAG, "startVoiceActivity not allowed on hidden session");
- return ActivityManager.START_CANCELED;
+ return ActivityManager.START_VOICE_HIDDEN_SESSION;
}
intent = new Intent(intent);
intent.addCategory(Intent.CATEGORY_VOICE);
diff --git a/telephony/java/android/telephony/ModemActivityInfo.java b/telephony/java/android/telephony/ModemActivityInfo.java
index 84883d8..03ce2d8 100644
--- a/telephony/java/android/telephony/ModemActivityInfo.java
+++ b/telephony/java/android/telephony/ModemActivityInfo.java
@@ -151,12 +151,24 @@
* @return if the record is valid
*/
public boolean isValid() {
- int totalTxTimeMs = 0;
- int txTime [] = getTxTimeMillis();
- for (int i = 0; i < TX_POWER_LEVELS; i++) {
- totalTxTimeMs += txTime[i];
+ for (int txVal : getTxTimeMillis()) {
+ if(txVal < 0) {
+ return false;
+ }
}
- return ((getIdleTimeMillis() >= 0) && (totalTxTimeMs >= 0)
- && (getSleepTimeMillis() >= 0) && (getIdleTimeMillis() >= 0));
+
+ return ((getIdleTimeMillis() >= 0) && (getSleepTimeMillis() >= 0)
+ && (getRxTimeMillis() >= 0) && (getEnergyUsed() >= 0) && !isEmpty());
+ }
+
+ private boolean isEmpty() {
+ for (int txVal : getTxTimeMillis()) {
+ if(txVal != 0) {
+ return false;
+ }
+ }
+
+ return ((getIdleTimeMillis() == 0) && (getSleepTimeMillis() == 0)
+ && (getRxTimeMillis() == 0) && (getEnergyUsed() == 0));
}
}