Merge "Allow notification listeners full DND access." into nyc-dev
diff --git a/Android.mk b/Android.mk
index ae5d67e..2017404 100644
--- a/Android.mk
+++ b/Android.mk
@@ -442,8 +442,6 @@
telephony/java/com/android/internal/telephony/ISms.aidl \
telephony/java/com/android/internal/telephony/ISub.aidl \
telephony/java/com/android/internal/telephony/ITelephony.aidl \
- telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl \
- telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl \
telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \
telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
wifi/java/android/net/wifi/IWifiManager.aidl \
diff --git a/api/current.txt b/api/current.txt
index 8d1b450..baef0a4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5897,7 +5897,7 @@
method public java.lang.CharSequence getDeviceOwnerLockScreenInfo();
method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
method public int getKeyguardDisabledFeatures(android.content.ComponentName);
- method public java.lang.String getLongSupportMessage(android.content.ComponentName);
+ method public java.lang.CharSequence getLongSupportMessage(android.content.ComponentName);
method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
method public long getMaximumTimeToLock(android.content.ComponentName);
method public int getOrganizationColor(android.content.ComponentName);
@@ -5920,7 +5920,7 @@
method public java.util.List<java.lang.String> getPermittedAccessibilityServices(android.content.ComponentName);
method public java.util.List<java.lang.String> getPermittedInputMethods(android.content.ComponentName);
method public boolean getScreenCaptureDisabled(android.content.ComponentName);
- method public java.lang.String getShortSupportMessage(android.content.ComponentName);
+ method public java.lang.CharSequence getShortSupportMessage(android.content.ComponentName);
method public boolean getStorageEncryption(android.content.ComponentName);
method public int getStorageEncryptionStatus();
method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
@@ -5971,7 +5971,7 @@
method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
- method public void setLongSupportMessage(android.content.ComponentName, java.lang.String);
+ method public void setLongSupportMessage(android.content.ComponentName, java.lang.CharSequence);
method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
method public void setMaximumTimeToLock(android.content.ComponentName, long);
@@ -5999,7 +5999,7 @@
method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public void setSecurityLoggingEnabled(android.content.ComponentName, boolean);
- method public void setShortSupportMessage(android.content.ComponentName, java.lang.String);
+ method public void setShortSupportMessage(android.content.ComponentName, java.lang.CharSequence);
method public boolean setStatusBarDisabled(android.content.ComponentName, boolean);
method public int setStorageEncryption(android.content.ComponentName, boolean);
method public void setSystemUpdatePolicy(android.content.ComponentName, android.app.admin.SystemUpdatePolicy);
@@ -6313,6 +6313,8 @@
method public static final long getMinimumPeriod();
method public int getNetworkType();
method public android.content.ComponentName getService();
+ method public long getTriggerContentMaxDelay();
+ method public long getTriggerContentUpdateDelay();
method public android.app.job.JobInfo.TriggerContentUri[] getTriggerContentUris();
method public boolean isPeriodic();
method public boolean isPersisted();
@@ -6343,6 +6345,8 @@
method public android.app.job.JobInfo.Builder setRequiredNetworkType(int);
method public android.app.job.JobInfo.Builder setRequiresCharging(boolean);
method public android.app.job.JobInfo.Builder setRequiresDeviceIdle(boolean);
+ method public android.app.job.JobInfo.Builder setTriggerContentMaxDelay(long);
+ method public android.app.job.JobInfo.Builder setTriggerContentUpdateDelay(long);
}
public static final class JobInfo.TriggerContentUri implements android.os.Parcelable {
@@ -8615,6 +8619,7 @@
field public static final java.lang.String ACTION_SENDTO = "android.intent.action.SENDTO";
field public static final java.lang.String ACTION_SEND_MULTIPLE = "android.intent.action.SEND_MULTIPLE";
field public static final java.lang.String ACTION_SET_WALLPAPER = "android.intent.action.SET_WALLPAPER";
+ field public static final java.lang.String ACTION_SHOW_APP_INFO = "android.intent.action.SHOW_APP_INFO";
field public static final java.lang.String ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN";
field public static final java.lang.String ACTION_SYNC = "android.intent.action.SYNC";
field public static final java.lang.String ACTION_SYSTEM_TUTORIAL = "android.intent.action.SYSTEM_TUTORIAL";
@@ -8709,6 +8714,7 @@
field public static final java.lang.String EXTRA_MIME_TYPES = "android.intent.extra.MIME_TYPES";
field public static final java.lang.String EXTRA_NOT_UNKNOWN_SOURCE = "android.intent.extra.NOT_UNKNOWN_SOURCE";
field public static final java.lang.String EXTRA_ORIGINATING_URI = "android.intent.extra.ORIGINATING_URI";
+ field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
field public static final java.lang.String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
field public static final java.lang.String EXTRA_PROCESS_TEXT = "android.intent.extra.PROCESS_TEXT";
field public static final java.lang.String EXTRA_PROCESS_TEXT_READONLY = "android.intent.extra.PROCESS_TEXT_READONLY";
diff --git a/api/system-current.txt b/api/system-current.txt
index b3bac02..d8545f1 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6040,7 +6040,7 @@
method public java.lang.String getDeviceOwnerNameOnAnyUser();
method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
method public int getKeyguardDisabledFeatures(android.content.ComponentName);
- method public java.lang.String getLongSupportMessage(android.content.ComponentName);
+ method public java.lang.CharSequence getLongSupportMessage(android.content.ComponentName);
method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
method public long getMaximumTimeToLock(android.content.ComponentName);
method public int getOrganizationColor(android.content.ComponentName);
@@ -6067,7 +6067,7 @@
method public android.content.ComponentName getProfileOwner() throws java.lang.IllegalArgumentException;
method public java.lang.String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException;
method public boolean getScreenCaptureDisabled(android.content.ComponentName);
- method public java.lang.String getShortSupportMessage(android.content.ComponentName);
+ method public java.lang.CharSequence getShortSupportMessage(android.content.ComponentName);
method public boolean getStorageEncryption(android.content.ComponentName);
method public int getStorageEncryptionStatus();
method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
@@ -6121,7 +6121,7 @@
method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
- method public void setLongSupportMessage(android.content.ComponentName, java.lang.String);
+ method public void setLongSupportMessage(android.content.ComponentName, java.lang.CharSequence);
method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
method public void setMaximumTimeToLock(android.content.ComponentName, long);
@@ -6149,7 +6149,7 @@
method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public void setSecurityLoggingEnabled(android.content.ComponentName, boolean);
- method public void setShortSupportMessage(android.content.ComponentName, java.lang.String);
+ method public void setShortSupportMessage(android.content.ComponentName, java.lang.CharSequence);
method public boolean setStatusBarDisabled(android.content.ComponentName, boolean);
method public int setStorageEncryption(android.content.ComponentName, boolean);
method public void setSystemUpdatePolicy(android.content.ComponentName, android.app.admin.SystemUpdatePolicy);
@@ -6581,6 +6581,8 @@
method public static final long getMinimumPeriod();
method public int getNetworkType();
method public android.content.ComponentName getService();
+ method public long getTriggerContentMaxDelay();
+ method public long getTriggerContentUpdateDelay();
method public android.app.job.JobInfo.TriggerContentUri[] getTriggerContentUris();
method public boolean isPeriodic();
method public boolean isPersisted();
@@ -6611,6 +6613,8 @@
method public android.app.job.JobInfo.Builder setRequiredNetworkType(int);
method public android.app.job.JobInfo.Builder setRequiresCharging(boolean);
method public android.app.job.JobInfo.Builder setRequiresDeviceIdle(boolean);
+ method public android.app.job.JobInfo.Builder setTriggerContentMaxDelay(long);
+ method public android.app.job.JobInfo.Builder setTriggerContentUpdateDelay(long);
}
public static final class JobInfo.TriggerContentUri implements android.os.Parcelable {
@@ -8934,6 +8938,7 @@
field public static final java.lang.String ACTION_SENDTO = "android.intent.action.SENDTO";
field public static final java.lang.String ACTION_SEND_MULTIPLE = "android.intent.action.SEND_MULTIPLE";
field public static final java.lang.String ACTION_SET_WALLPAPER = "android.intent.action.SET_WALLPAPER";
+ field public static final java.lang.String ACTION_SHOW_APP_INFO = "android.intent.action.SHOW_APP_INFO";
field public static final java.lang.String ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN";
field public static final java.lang.String ACTION_SYNC = "android.intent.action.SYNC";
field public static final java.lang.String ACTION_SYSTEM_TUTORIAL = "android.intent.action.SYSTEM_TUTORIAL";
diff --git a/api/test-current.txt b/api/test-current.txt
index fcfe489..6a0f071 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -5901,7 +5901,7 @@
method public java.lang.CharSequence getDeviceOwnerLockScreenInfo();
method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
method public int getKeyguardDisabledFeatures(android.content.ComponentName);
- method public java.lang.String getLongSupportMessage(android.content.ComponentName);
+ method public java.lang.CharSequence getLongSupportMessage(android.content.ComponentName);
method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
method public long getMaximumTimeToLock(android.content.ComponentName);
method public int getOrganizationColor(android.content.ComponentName);
@@ -5924,7 +5924,7 @@
method public java.util.List<java.lang.String> getPermittedAccessibilityServices(android.content.ComponentName);
method public java.util.List<java.lang.String> getPermittedInputMethods(android.content.ComponentName);
method public boolean getScreenCaptureDisabled(android.content.ComponentName);
- method public java.lang.String getShortSupportMessage(android.content.ComponentName);
+ method public java.lang.CharSequence getShortSupportMessage(android.content.ComponentName);
method public boolean getStorageEncryption(android.content.ComponentName);
method public int getStorageEncryptionStatus();
method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
@@ -5975,7 +5975,7 @@
method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
- method public void setLongSupportMessage(android.content.ComponentName, java.lang.String);
+ method public void setLongSupportMessage(android.content.ComponentName, java.lang.CharSequence);
method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
method public void setMaximumTimeToLock(android.content.ComponentName, long);
@@ -6003,7 +6003,7 @@
method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public void setSecurityLoggingEnabled(android.content.ComponentName, boolean);
- method public void setShortSupportMessage(android.content.ComponentName, java.lang.String);
+ method public void setShortSupportMessage(android.content.ComponentName, java.lang.CharSequence);
method public boolean setStatusBarDisabled(android.content.ComponentName, boolean);
method public int setStorageEncryption(android.content.ComponentName, boolean);
method public void setSystemUpdatePolicy(android.content.ComponentName, android.app.admin.SystemUpdatePolicy);
@@ -6317,6 +6317,8 @@
method public static final long getMinimumPeriod();
method public int getNetworkType();
method public android.content.ComponentName getService();
+ method public long getTriggerContentMaxDelay();
+ method public long getTriggerContentUpdateDelay();
method public android.app.job.JobInfo.TriggerContentUri[] getTriggerContentUris();
method public boolean isPeriodic();
method public boolean isPersisted();
@@ -6347,6 +6349,8 @@
method public android.app.job.JobInfo.Builder setRequiredNetworkType(int);
method public android.app.job.JobInfo.Builder setRequiresCharging(boolean);
method public android.app.job.JobInfo.Builder setRequiresDeviceIdle(boolean);
+ method public android.app.job.JobInfo.Builder setTriggerContentMaxDelay(long);
+ method public android.app.job.JobInfo.Builder setTriggerContentUpdateDelay(long);
}
public static final class JobInfo.TriggerContentUri implements android.os.Parcelable {
@@ -8622,6 +8626,7 @@
field public static final java.lang.String ACTION_SENDTO = "android.intent.action.SENDTO";
field public static final java.lang.String ACTION_SEND_MULTIPLE = "android.intent.action.SEND_MULTIPLE";
field public static final java.lang.String ACTION_SET_WALLPAPER = "android.intent.action.SET_WALLPAPER";
+ field public static final java.lang.String ACTION_SHOW_APP_INFO = "android.intent.action.SHOW_APP_INFO";
field public static final java.lang.String ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN";
field public static final java.lang.String ACTION_SYNC = "android.intent.action.SYNC";
field public static final java.lang.String ACTION_SYSTEM_TUTORIAL = "android.intent.action.SYSTEM_TUTORIAL";
@@ -8716,6 +8721,7 @@
field public static final java.lang.String EXTRA_MIME_TYPES = "android.intent.extra.MIME_TYPES";
field public static final java.lang.String EXTRA_NOT_UNKNOWN_SOURCE = "android.intent.extra.NOT_UNKNOWN_SOURCE";
field public static final java.lang.String EXTRA_ORIGINATING_URI = "android.intent.extra.ORIGINATING_URI";
+ field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
field public static final java.lang.String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
field public static final java.lang.String EXTRA_PROCESS_TEXT = "android.intent.extra.PROCESS_TEXT";
field public static final java.lang.String EXTRA_PROCESS_TEXT_READONLY = "android.intent.extra.PROCESS_TEXT_READONLY";
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 3385a17..e788d27 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -16,6 +16,9 @@
package android.animation;
+import android.app.ActivityThread;
+import android.app.Application;
+import android.os.Build;
import android.util.ArrayMap;
import android.util.Log;
@@ -133,10 +136,25 @@
// The total duration of finishing all the Animators in the set.
private long mTotalDuration = 0;
+ // In pre-N releases, calling end() before start() on an animator set is no-op. But that is not
+ // consistent with the behavior for other animator types. In order to keep the behavior
+ // consistent within Animation framework, when end() is called without start(), we will start
+ // the animator set and immediately end it for N and forward.
+ private final boolean mShouldIgnoreEndWithoutStart;
+
public AnimatorSet() {
super();
mNodeMap.put(mDelayAnim, mRootNode);
mNodes.add(mRootNode);
+ // Set the flag to ignore calling end() without start() for pre-N releases
+ Application app = ActivityThread.currentApplication();
+ if (app == null || app.getApplicationInfo() == null) {
+ mShouldIgnoreEndWithoutStart = true;
+ } else if (app.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) {
+ mShouldIgnoreEndWithoutStart = true;
+ } else {
+ mShouldIgnoreEndWithoutStart = false;
+ }
}
/**
@@ -365,6 +383,9 @@
*/
@Override
public void end() {
+ if (mShouldIgnoreEndWithoutStart && !isStarted()) {
+ return;
+ }
mTerminated = true;
if (isStarted()) {
endRemainingAnimations();
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index c6a5152..31035a7 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -1200,13 +1200,17 @@
boolean animateBasedOnTime(long currentTime) {
boolean done = false;
if (mRunning) {
- final float fraction = getScaledDuration() > 0 ?
- (float)(currentTime - mStartTime) / getScaledDuration() : 1f;
+ final long scaledDuration = getScaledDuration();
+ final float fraction = scaledDuration > 0 ?
+ (float)(currentTime - mStartTime) / scaledDuration : 1f;
final float lastFraction = mOverallFraction;
final boolean newIteration = (int) fraction > (int) lastFraction;
final boolean lastIterationFinished = (fraction >= mRepeatCount + 1) &&
(mRepeatCount != INFINITE);
- if (newIteration && !lastIterationFinished) {
+ if (scaledDuration == 0) {
+ // 0 duration animator, ignore the repeat count and skip to the end
+ done = true;
+ } else if (newIteration && !lastIterationFinished) {
// Time to repeat
if (mListeners != null) {
int numListeners = mListeners.size();
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 4c4f128..aef92cf 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -29,6 +29,7 @@
import android.content.res.ResourcesKey;
import android.hardware.display.DisplayManagerGlobal;
import android.os.IBinder;
+import android.os.Trace;
import android.util.ArrayMap;
import android.util.DisplayMetrics;
import android.util.LocaleList;
@@ -430,37 +431,44 @@
@Nullable Configuration overrideConfig,
@NonNull CompatibilityInfo compatInfo,
@Nullable ClassLoader classLoader) {
- final ResourcesKey key = new ResourcesKey(
- resDir,
- splitResDirs,
- overlayDirs,
- libDirs,
- displayId,
- overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
- compatInfo);
- classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_RESOURCES,
+ "ResourcesManager#createBaseActivityResources");
+ final ResourcesKey key = new ResourcesKey(
+ resDir,
+ splitResDirs,
+ overlayDirs,
+ libDirs,
+ displayId,
+ overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
+ compatInfo);
+ classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
- if (DEBUG) {
- Slog.d(TAG, "createBaseActivityResources activity=" + activityToken
- + " with key=" + key);
- }
-
- synchronized (this) {
- final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
- activityToken);
-
- if (overrideConfig != null) {
- activityResources.overrideConfig.setTo(overrideConfig);
- } else {
- activityResources.overrideConfig.setToDefaults();
+ if (DEBUG) {
+ Slog.d(TAG, "createBaseActivityResources activity=" + activityToken
+ + " with key=" + key);
}
+
+ synchronized (this) {
+ final ActivityResources activityResources =
+ getOrCreateActivityResourcesStructLocked(
+ activityToken);
+
+ if (overrideConfig != null) {
+ activityResources.overrideConfig.setTo(overrideConfig);
+ } else {
+ activityResources.overrideConfig.setToDefaults();
+ }
+ }
+
+ // Update any existing Activity Resources references.
+ updateResourcesForActivity(activityToken, overrideConfig);
+
+ // Now request an actual Resources object.
+ return getOrCreateResources(activityToken, key, classLoader);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
}
-
- // Update any existing Activity Resources references.
- updateResourcesForActivity(activityToken, overrideConfig);
-
- // Now request an actual Resources object.
- return getOrCreateResources(activityToken, key, classLoader);
}
/**
@@ -490,8 +498,8 @@
}
if (activityToken != null) {
- final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
- activityToken);
+ final ActivityResources activityResources =
+ getOrCreateActivityResourcesStructLocked(activityToken);
// Clean up any dead references so they don't pile up.
ArrayUtils.unstableRemoveIf(activityResources.activityResources,
@@ -539,6 +547,7 @@
final String[] systemLocales = findSystemLocales
? AssetManager.getSystem().getLocales() : null;
final String[] nonSystemLocales = resourcesImpl.getAssets().getNonSystemLocales();
+
// Avoid checking for non-pseudo-locales if we already know there were some from a previous
// Resources. The default value (for when hasNonSystemLocales is true) doesn't matter,
// since mHasNonSystemLocales will also be true, and thus isPseudoLocalesOnly would not be
@@ -613,16 +622,21 @@
@Nullable Configuration overrideConfig,
@NonNull CompatibilityInfo compatInfo,
@Nullable ClassLoader classLoader) {
- final ResourcesKey key = new ResourcesKey(
- resDir,
- splitResDirs,
- overlayDirs,
- libDirs,
- displayId,
- overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
- compatInfo);
- classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
- return getOrCreateResources(activityToken, key, classLoader);
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "ResourcesManager#getResources");
+ final ResourcesKey key = new ResourcesKey(
+ resDir,
+ splitResDirs,
+ overlayDirs,
+ libDirs,
+ displayId,
+ overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
+ compatInfo);
+ classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
+ return getOrCreateResources(activityToken, key, classLoader);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+ }
}
/**
@@ -636,93 +650,104 @@
*/
public void updateResourcesForActivity(@NonNull IBinder activityToken,
@Nullable Configuration overrideConfig) {
- synchronized (this) {
- final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
- activityToken);
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_RESOURCES,
+ "ResourcesManager#updateResourcesForActivity");
+ synchronized (this) {
+ final ActivityResources activityResources =
+ getOrCreateActivityResourcesStructLocked(activityToken);
- if (Objects.equals(activityResources.overrideConfig, overrideConfig)) {
- // They are the same, no work to do.
- return;
- }
-
- // Grab a copy of the old configuration so we can create the delta's of each
- // Resources object associated with this Activity.
- final Configuration oldConfig = new Configuration(activityResources.overrideConfig);
-
- // Update the Activity's base override.
- if (overrideConfig != null) {
- activityResources.overrideConfig.setTo(overrideConfig);
- } else {
- activityResources.overrideConfig.setToDefaults();
- }
-
- if (DEBUG) {
- Throwable here = new Throwable();
- here.fillInStackTrace();
- Slog.d(TAG, "updating resources override for activity=" + activityToken
- + " from oldConfig=" + Configuration.resourceQualifierString(oldConfig)
- + " to newConfig="
- + Configuration.resourceQualifierString(activityResources.overrideConfig),
- here);
- }
-
- final boolean activityHasOverrideConfig =
- !activityResources.overrideConfig.equals(Configuration.EMPTY);
-
- // Rebase each Resources associated with this Activity.
- final int refCount = activityResources.activityResources.size();
- for (int i = 0; i < refCount; i++) {
- WeakReference<Resources> weakResRef = activityResources.activityResources.get(i);
- Resources resources = weakResRef.get();
- if (resources == null) {
- continue;
+ if (Objects.equals(activityResources.overrideConfig, overrideConfig)) {
+ // They are the same, no work to do.
+ return;
}
- // Extract the ResourcesKey that was last used to create the Resources for this
- // activity.
- final ResourcesKey oldKey = findKeyForResourceImplLocked(resources.getImpl());
- if (oldKey == null) {
- Slog.e(TAG, "can't find ResourcesKey for resources impl="
- + resources.getImpl());
- continue;
- }
+ // Grab a copy of the old configuration so we can create the delta's of each
+ // Resources object associated with this Activity.
+ final Configuration oldConfig = new Configuration(activityResources.overrideConfig);
- // Build the new override configuration for this ResourcesKey.
- final Configuration rebasedOverrideConfig = new Configuration();
+ // Update the Activity's base override.
if (overrideConfig != null) {
- rebasedOverrideConfig.setTo(overrideConfig);
+ activityResources.overrideConfig.setTo(overrideConfig);
+ } else {
+ activityResources.overrideConfig.setToDefaults();
}
- if (activityHasOverrideConfig && oldKey.hasOverrideConfiguration()) {
- // Generate a delta between the old base Activity override configuration and
- // the actual final override configuration that was used to figure out the real
- // delta this Resources object wanted.
- Configuration overrideOverrideConfig = Configuration.generateDelta(
- oldConfig, oldKey.mOverrideConfiguration);
- rebasedOverrideConfig.updateFrom(overrideOverrideConfig);
- }
-
- // Create the new ResourcesKey with the rebased override config.
- final ResourcesKey newKey = new ResourcesKey(oldKey.mResDir, oldKey.mSplitResDirs,
- oldKey.mOverlayDirs, oldKey.mLibDirs, oldKey.mDisplayId,
- rebasedOverrideConfig, oldKey.mCompatInfo);
-
if (DEBUG) {
- Slog.d(TAG, "rebasing ref=" + resources + " from oldKey=" + oldKey
- + " to newKey=" + newKey);
+ Throwable here = new Throwable();
+ here.fillInStackTrace();
+ Slog.d(TAG, "updating resources override for activity=" + activityToken
+ + " from oldConfig="
+ + Configuration.resourceQualifierString(oldConfig)
+ + " to newConfig="
+ + Configuration.resourceQualifierString(
+ activityResources.overrideConfig),
+ here);
}
- ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(newKey);
- if (resourcesImpl == null) {
- resourcesImpl = createResourcesImpl(newKey);
- mResourceImpls.put(newKey, new WeakReference<>(resourcesImpl));
- }
+ final boolean activityHasOverrideConfig =
+ !activityResources.overrideConfig.equals(Configuration.EMPTY);
- if (resourcesImpl != resources.getImpl()) {
- // Set the ResourcesImpl, updating it for all users of this Resources object.
- resources.setImpl(resourcesImpl);
+ // Rebase each Resources associated with this Activity.
+ final int refCount = activityResources.activityResources.size();
+ for (int i = 0; i < refCount; i++) {
+ WeakReference<Resources> weakResRef = activityResources.activityResources.get(
+ i);
+ Resources resources = weakResRef.get();
+ if (resources == null) {
+ continue;
+ }
+
+ // Extract the ResourcesKey that was last used to create the Resources for this
+ // activity.
+ final ResourcesKey oldKey = findKeyForResourceImplLocked(resources.getImpl());
+ if (oldKey == null) {
+ Slog.e(TAG, "can't find ResourcesKey for resources impl="
+ + resources.getImpl());
+ continue;
+ }
+
+ // Build the new override configuration for this ResourcesKey.
+ final Configuration rebasedOverrideConfig = new Configuration();
+ if (overrideConfig != null) {
+ rebasedOverrideConfig.setTo(overrideConfig);
+ }
+
+ if (activityHasOverrideConfig && oldKey.hasOverrideConfiguration()) {
+ // Generate a delta between the old base Activity override configuration and
+ // the actual final override configuration that was used to figure out the
+ // real delta this Resources object wanted.
+ Configuration overrideOverrideConfig = Configuration.generateDelta(
+ oldConfig, oldKey.mOverrideConfiguration);
+ rebasedOverrideConfig.updateFrom(overrideOverrideConfig);
+ }
+
+ // Create the new ResourcesKey with the rebased override config.
+ final ResourcesKey newKey = new ResourcesKey(oldKey.mResDir,
+ oldKey.mSplitResDirs,
+ oldKey.mOverlayDirs, oldKey.mLibDirs, oldKey.mDisplayId,
+ rebasedOverrideConfig, oldKey.mCompatInfo);
+
+ if (DEBUG) {
+ Slog.d(TAG, "rebasing ref=" + resources + " from oldKey=" + oldKey
+ + " to newKey=" + newKey);
+ }
+
+ ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(newKey);
+ if (resourcesImpl == null) {
+ resourcesImpl = createResourcesImpl(newKey);
+ mResourceImpls.put(newKey, new WeakReference<>(resourcesImpl));
+ }
+
+ if (resourcesImpl != resources.getImpl()) {
+ // Set the ResourcesImpl, updating it for all users of this Resources
+ // object.
+ resources.setImpl(resourcesImpl);
+ }
}
}
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
}
}
@@ -745,86 +770,95 @@
public final boolean applyConfigurationToResourcesLocked(@NonNull Configuration config,
@Nullable CompatibilityInfo compat) {
- if (!mResConfiguration.isOtherSeqNewer(config) && compat == null) {
- if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Skipping new config: curSeq="
- + mResConfiguration.seq + ", newSeq=" + config.seq);
- return false;
- }
- int changes = mResConfiguration.updateFrom(config);
- // Things might have changed in display manager, so clear the cached displays.
- mDisplays.clear();
- DisplayMetrics defaultDisplayMetrics = getDisplayMetrics();
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_RESOURCES,
+ "ResourcesManager#applyConfigurationToResourcesLocked");
- if (compat != null && (mResCompatibilityInfo == null ||
- !mResCompatibilityInfo.equals(compat))) {
- mResCompatibilityInfo = compat;
- changes |= ActivityInfo.CONFIG_SCREEN_LAYOUT
- | ActivityInfo.CONFIG_SCREEN_SIZE
- | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
- }
+ if (!mResConfiguration.isOtherSeqNewer(config) && compat == null) {
+ if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Skipping new config: curSeq="
+ + mResConfiguration.seq + ", newSeq=" + config.seq);
+ return false;
+ }
+ int changes = mResConfiguration.updateFrom(config);
+ // Things might have changed in display manager, so clear the cached displays.
+ mDisplays.clear();
+ DisplayMetrics defaultDisplayMetrics = getDisplayMetrics();
- Configuration localeAdjustedConfig = config;
- final LocaleList configLocales = config.getLocales();
- if (!configLocales.isEmpty()) {
- setDefaultLocalesLocked(configLocales);
- final LocaleList adjustedLocales = LocaleList.getAdjustedDefault();
- if (adjustedLocales != configLocales) { // has the same result as .equals() in this case
- // The first locale in the list was not chosen. So we create a modified
- // configuration with the adjusted locales (which moves the chosen locale to the
- // front).
- localeAdjustedConfig = new Configuration();
- localeAdjustedConfig.setTo(config);
- localeAdjustedConfig.setLocales(adjustedLocales);
- // Also adjust the locale list in mResConfiguration, so that the Resources created
- // later would have the same locale list.
- if (!mResConfiguration.getLocales().equals(adjustedLocales)) {
- mResConfiguration.setLocales(adjustedLocales);
- changes |= ActivityInfo.CONFIG_LOCALE;
+ if (compat != null && (mResCompatibilityInfo == null ||
+ !mResCompatibilityInfo.equals(compat))) {
+ mResCompatibilityInfo = compat;
+ changes |= ActivityInfo.CONFIG_SCREEN_LAYOUT
+ | ActivityInfo.CONFIG_SCREEN_SIZE
+ | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
+ }
+
+ Configuration localeAdjustedConfig = config;
+ final LocaleList configLocales = config.getLocales();
+ if (!configLocales.isEmpty()) {
+ setDefaultLocalesLocked(configLocales);
+ final LocaleList adjustedLocales = LocaleList.getAdjustedDefault();
+ if (adjustedLocales
+ != configLocales) { // has the same result as .equals() in this case
+ // The first locale in the list was not chosen. So we create a modified
+ // configuration with the adjusted locales (which moves the chosen locale to the
+ // front).
+ localeAdjustedConfig = new Configuration();
+ localeAdjustedConfig.setTo(config);
+ localeAdjustedConfig.setLocales(adjustedLocales);
+ // Also adjust the locale list in mResConfiguration, so that the Resources
+ // created later would have the same locale list.
+ if (!mResConfiguration.getLocales().equals(adjustedLocales)) {
+ mResConfiguration.setLocales(adjustedLocales);
+ changes |= ActivityInfo.CONFIG_LOCALE;
+ }
}
}
- }
- Resources.updateSystemConfiguration(localeAdjustedConfig, defaultDisplayMetrics, compat);
+ Resources.updateSystemConfiguration(localeAdjustedConfig, defaultDisplayMetrics,
+ compat);
- ApplicationPackageManager.configurationChanged();
- //Slog.i(TAG, "Configuration changed in " + currentPackageName());
+ ApplicationPackageManager.configurationChanged();
+ //Slog.i(TAG, "Configuration changed in " + currentPackageName());
- Configuration tmpConfig = null;
+ Configuration tmpConfig = null;
- for (int i = mResourceImpls.size() - 1; i >= 0; i--) {
- ResourcesKey key = mResourceImpls.keyAt(i);
- ResourcesImpl r = mResourceImpls.valueAt(i).get();
- if (r != null) {
- if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
- + r + " config to: " + localeAdjustedConfig);
- int displayId = key.mDisplayId;
- boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
- DisplayMetrics dm = defaultDisplayMetrics;
- final boolean hasOverrideConfiguration = key.hasOverrideConfiguration();
- if (!isDefaultDisplay || hasOverrideConfiguration) {
- if (tmpConfig == null) {
- tmpConfig = new Configuration();
+ for (int i = mResourceImpls.size() - 1; i >= 0; i--) {
+ ResourcesKey key = mResourceImpls.keyAt(i);
+ ResourcesImpl r = mResourceImpls.valueAt(i).get();
+ if (r != null) {
+ if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
+ + r + " config to: " + localeAdjustedConfig);
+ int displayId = key.mDisplayId;
+ boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
+ DisplayMetrics dm = defaultDisplayMetrics;
+ final boolean hasOverrideConfiguration = key.hasOverrideConfiguration();
+ if (!isDefaultDisplay || hasOverrideConfiguration) {
+ if (tmpConfig == null) {
+ tmpConfig = new Configuration();
+ }
+ tmpConfig.setTo(localeAdjustedConfig);
+ if (!isDefaultDisplay) {
+ dm = getDisplayMetrics(displayId);
+ applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig);
+ }
+ if (hasOverrideConfiguration) {
+ tmpConfig.updateFrom(key.mOverrideConfiguration);
+ }
+ r.updateConfiguration(tmpConfig, dm, compat);
+ } else {
+ r.updateConfiguration(localeAdjustedConfig, dm, compat);
}
- tmpConfig.setTo(localeAdjustedConfig);
- if (!isDefaultDisplay) {
- dm = getDisplayMetrics(displayId);
- applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig);
- }
- if (hasOverrideConfiguration) {
- tmpConfig.updateFrom(key.mOverrideConfiguration);
- }
- r.updateConfiguration(tmpConfig, dm, compat);
+ //Slog.i(TAG, "Updated app resources " + v.getKey()
+ // + " " + r + ": " + r.getConfiguration());
} else {
- r.updateConfiguration(localeAdjustedConfig, dm, compat);
+ //Slog.i(TAG, "Removing old resources " + v.getKey());
+ mResourceImpls.removeAt(i);
}
- //Slog.i(TAG, "Updated app resources " + v.getKey()
- // + " " + r + ": " + r.getConfiguration());
- } else {
- //Slog.i(TAG, "Removing old resources " + v.getKey());
- mResourceImpls.removeAt(i);
}
- }
- return changes != 0;
+ return changes != 0;
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+ }
}
}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index d5d4ca7..cd6e572 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -532,7 +532,8 @@
public WifiScanner createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(Context.WIFI_SCANNING_SERVICE);
IWifiScanner service = IWifiScanner.Stub.asInterface(b);
- return new WifiScanner(ctx.getOuterContext(), service);
+ return new WifiScanner(ctx.getOuterContext(), service,
+ ConnectivityThread.getInstanceLooper());
}});
registerService(Context.WIFI_RTT_SERVICE, RttManager.class,
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index a7bb348..269089e 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -5762,7 +5762,7 @@
* @throws SecurityException if {@code admin} is not an active administrator.
*/
public void setShortSupportMessage(@NonNull ComponentName admin,
- @Nullable String message) {
+ @Nullable CharSequence message) {
if (mService != null) {
try {
mService.setShortSupportMessage(admin, message);
@@ -5776,11 +5776,11 @@
* Called by a device admin to get the short support message.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
- * @return The message set by {@link #setShortSupportMessage(ComponentName, String)} or null if
- * no message has been set.
+ * @return The message set by {@link #setShortSupportMessage(ComponentName, CharSequence)} or
+ * null if no message has been set.
* @throws SecurityException if {@code admin} is not an active administrator.
*/
- public String getShortSupportMessage(@NonNull ComponentName admin) {
+ public CharSequence getShortSupportMessage(@NonNull ComponentName admin) {
if (mService != null) {
try {
return mService.getShortSupportMessage(admin);
@@ -5806,7 +5806,7 @@
* @throws SecurityException if {@code admin} is not an active administrator.
*/
public void setLongSupportMessage(@NonNull ComponentName admin,
- @Nullable String message) {
+ @Nullable CharSequence message) {
if (mService != null) {
try {
mService.setLongSupportMessage(admin, message);
@@ -5820,11 +5820,11 @@
* Called by a device admin to get the long support message.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
- * @return The message set by {@link #setLongSupportMessage(ComponentName, String)} or null if
- * no message has been set.
+ * @return The message set by {@link #setLongSupportMessage(ComponentName, CharSequence)} or
+ * null if no message has been set.
* @throws SecurityException if {@code admin} is not an active administrator.
*/
- public String getLongSupportMessage(@NonNull ComponentName admin) {
+ public CharSequence getLongSupportMessage(@NonNull ComponentName admin) {
if (mService != null) {
try {
return mService.getLongSupportMessage(admin);
@@ -5840,11 +5840,12 @@
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param userHandle user id the admin is running as.
- * @return The message set by {@link #setShortSupportMessage(ComponentName, String)}
+ * @return The message set by {@link #setShortSupportMessage(ComponentName, CharSequence)}
*
* @hide
*/
- public String getShortSupportMessageForUser(@NonNull ComponentName admin, int userHandle) {
+ public CharSequence getShortSupportMessageForUser(@NonNull ComponentName admin,
+ int userHandle) {
if (mService != null) {
try {
return mService.getShortSupportMessageForUser(admin, userHandle);
@@ -5861,11 +5862,11 @@
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param userHandle user id the admin is running as.
- * @return The message set by {@link #setLongSupportMessage(ComponentName, String)}
+ * @return The message set by {@link #setLongSupportMessage(ComponentName, CharSequence)}
*
* @hide
*/
- public String getLongSupportMessageForUser(@NonNull ComponentName admin, int userHandle) {
+ public CharSequence getLongSupportMessageForUser(@NonNull ComponentName admin, int userHandle) {
if (mService != null) {
try {
return mService.getLongSupportMessageForUser(admin, userHandle);
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 2801b87..cba64c2 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -269,13 +269,13 @@
String getWifiMacAddress(in ComponentName admin);
void reboot(in ComponentName admin);
- void setShortSupportMessage(in ComponentName admin, in String message);
- String getShortSupportMessage(in ComponentName admin);
- void setLongSupportMessage(in ComponentName admin, in String message);
- String getLongSupportMessage(in ComponentName admin);
+ void setShortSupportMessage(in ComponentName admin, in CharSequence message);
+ CharSequence getShortSupportMessage(in ComponentName admin);
+ void setLongSupportMessage(in ComponentName admin, in CharSequence message);
+ CharSequence getLongSupportMessage(in ComponentName admin);
- String getShortSupportMessageForUser(in ComponentName admin, int userHandle);
- String getLongSupportMessageForUser(in ComponentName admin, int userHandle);
+ CharSequence getShortSupportMessageForUser(in ComponentName admin, int userHandle);
+ CharSequence getLongSupportMessageForUser(in ComponentName admin, int userHandle);
boolean isSeparateProfileChallengeAllowed(int userHandle);
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index 9b4f43a..c84a0dc 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -138,12 +138,28 @@
*/
public static final int PRIORITY_TOP_APP = 40;
+ /**
+ * Adjustment of {@link #getPriority} if the app has often (50% or more of the time)
+ * been running jobs.
+ * @hide
+ */
+ public static final int PRIORITY_ADJ_OFTEN_RUNNING = -40;
+
+ /**
+ * Adjustment of {@link #getPriority} if the app has always (90% or more of the time)
+ * been running jobs.
+ * @hide
+ */
+ public static final int PRIORITY_ADJ_ALWAYS_RUNNING = -80;
+
private final int jobId;
private final PersistableBundle extras;
private final ComponentName service;
private final boolean requireCharging;
private final boolean requireDeviceIdle;
private final TriggerContentUri[] triggerContentUris;
+ private final long triggerContentUpdateDelay;
+ private final long triggerContentMaxDelay;
private final boolean hasEarlyConstraint;
private final boolean hasLateConstraint;
private final int networkType;
@@ -207,6 +223,22 @@
}
/**
+ * When triggering on content URI changes, this is the delay from when a change
+ * is detected until the job is scheduled.
+ */
+ public long getTriggerContentUpdateDelay() {
+ return triggerContentUpdateDelay;
+ }
+
+ /**
+ * When triggering on content URI changes, this is the maximum delay we will
+ * use before scheduling the job.
+ */
+ public long getTriggerContentMaxDelay() {
+ return triggerContentMaxDelay;
+ }
+
+ /**
* One of {@link android.app.job.JobInfo#NETWORK_TYPE_ANY},
* {@link android.app.job.JobInfo#NETWORK_TYPE_NONE}, or
* {@link android.app.job.JobInfo#NETWORK_TYPE_UNMETERED}.
@@ -307,6 +339,8 @@
requireCharging = in.readInt() == 1;
requireDeviceIdle = in.readInt() == 1;
triggerContentUris = in.createTypedArray(TriggerContentUri.CREATOR);
+ triggerContentUpdateDelay = in.readLong();
+ triggerContentMaxDelay = in.readLong();
networkType = in.readInt();
minLatencyMillis = in.readLong();
maxExecutionDelayMillis = in.readLong();
@@ -330,6 +364,8 @@
triggerContentUris = b.mTriggerContentUris != null
? b.mTriggerContentUris.toArray(new TriggerContentUri[b.mTriggerContentUris.size()])
: null;
+ triggerContentUpdateDelay = b.mTriggerContentUpdateDelay;
+ triggerContentMaxDelay = b.mTriggerContentMaxDelay;
networkType = b.mNetworkType;
minLatencyMillis = b.mMinLatencyMillis;
maxExecutionDelayMillis = b.mMaxExecutionDelayMillis;
@@ -357,6 +393,8 @@
out.writeInt(requireCharging ? 1 : 0);
out.writeInt(requireDeviceIdle ? 1 : 0);
out.writeTypedArray(triggerContentUris, flags);
+ out.writeLong(triggerContentUpdateDelay);
+ out.writeLong(triggerContentMaxDelay);
out.writeInt(networkType);
out.writeLong(minLatencyMillis);
out.writeLong(maxExecutionDelayMillis);
@@ -468,6 +506,8 @@
private boolean mRequiresDeviceIdle;
private int mNetworkType;
private ArrayList<TriggerContentUri> mTriggerContentUris;
+ private long mTriggerContentUpdateDelay = -1;
+ private long mTriggerContentMaxDelay = -1;
private boolean mIsPersisted;
// One-off parameters.
private long mMinLatencyMillis;
@@ -574,6 +614,27 @@
}
/**
+ * Set the delay (in milliseconds) from when a content change is detected until
+ * the job is scheduled. If there are more changes during that time, the delay
+ * will be reset to start at the time of the most recent change.
+ * @param durationMs Delay after most recent content change, in milliseconds.
+ */
+ public Builder setTriggerContentUpdateDelay(long durationMs) {
+ mTriggerContentUpdateDelay = durationMs;
+ return this;
+ }
+
+ /**
+ * Set the maximum total delay (in milliseconds) that is allowed from the first
+ * time a content change is detected until the job is scheduled.
+ * @param durationMs Delay after initial content change, in milliseconds.
+ */
+ public Builder setTriggerContentMaxDelay(long durationMs) {
+ mTriggerContentMaxDelay = durationMs;
+ return this;
+ }
+
+ /**
* Specify that this job should recur with the provided interval, not more than once per
* period. You have no control over when within this interval this job will be executed,
* only the guarantee that it will be executed at most once within this interval.
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 7e67e8d..831de4a 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -765,6 +765,19 @@
= "android.intent.action.APPLICATION_PREFERENCES";
/**
+ * Activity Action: Launch an activity showing the app information.
+ * For applications which install other applications (such as app stores), it is recommended
+ * to handle this action for providing the app information to the user.
+ *
+ * <p>Input: {@link #EXTRA_PACKAGE_NAME} specifies the package whose information needs
+ * to be displayed.
+ * <p>Output: Nothing.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_SHOW_APP_INFO
+ = "android.intent.action.SHOW_APP_INFO";
+
+ /**
* Represents a shortcut/live folder icon resource.
*
* @see Intent#ACTION_CREATE_SHORTCUT
@@ -1683,9 +1696,7 @@
* Type: String
* </p>
*
- * @hide
*/
- @SystemApi
public static final String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
/**
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 79eff4f..98a8904 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -1590,16 +1590,16 @@
new Key<Integer>("android.control.videoStabilizationMode", int.class);
/**
- * <p>The amount of additional sesnsitivity boost applied to output images
+ * <p>The amount of additional sensitivity boost applied to output images
* after RAW sensor data is captured.</p>
* <p>Some camera devices support additional digital sensitivity boosting in the
* camera processing pipeline after sensor RAW image is captured.
* Such a boost will be applied to YUV/JPEG format output images but will not
* have effect on RAW output formats like RAW_SENSOR, RAW10, RAW12 or RAW_OPAQUE.</p>
- * <p>This key is optional. Applications can assume there is no boost applied
- * after RAW is captured if this key is not available.
- * When this key is available, the sensitivity boost value must be within
- * {@link CameraCharacteristics#CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE android.control.postRawSensitivityBoostRange}.</p>
+ * <p>This key will be <code>null</code> for devices that do not support any RAW format
+ * outputs. For devices that do support RAW format outputs, this key will always
+ * present, and if a device does not support post RAW sensitivity boost, it will
+ * list <code>100</code> in this key.</p>
* <p>If the camera device cannot apply the exact boost requested, it will reduce the
* boost to the nearest supported value.
* The final boost value used will be available in the output capture result.</p>
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 4f41e1c..ddf90a8 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2097,16 +2097,16 @@
new Key<Integer>("android.control.videoStabilizationMode", int.class);
/**
- * <p>The amount of additional sesnsitivity boost applied to output images
+ * <p>The amount of additional sensitivity boost applied to output images
* after RAW sensor data is captured.</p>
* <p>Some camera devices support additional digital sensitivity boosting in the
* camera processing pipeline after sensor RAW image is captured.
* Such a boost will be applied to YUV/JPEG format output images but will not
* have effect on RAW output formats like RAW_SENSOR, RAW10, RAW12 or RAW_OPAQUE.</p>
- * <p>This key is optional. Applications can assume there is no boost applied
- * after RAW is captured if this key is not available.
- * When this key is available, the sensitivity boost value must be within
- * {@link CameraCharacteristics#CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE android.control.postRawSensitivityBoostRange}.</p>
+ * <p>This key will be <code>null</code> for devices that do not support any RAW format
+ * outputs. For devices that do support RAW format outputs, this key will always
+ * present, and if a device does not support post RAW sensitivity boost, it will
+ * list <code>100</code> in this key.</p>
* <p>If the camera device cannot apply the exact boost requested, it will reduce the
* boost to the nearest supported value.
* The final boost value used will be available in the output capture result.</p>
diff --git a/core/java/android/service/carrier/CarrierIdentifier.java b/core/java/android/service/carrier/CarrierIdentifier.java
index 495fea6..a70c24d 100644
--- a/core/java/android/service/carrier/CarrierIdentifier.java
+++ b/core/java/android/service/carrier/CarrierIdentifier.java
@@ -105,6 +105,18 @@
out.writeString(mGid2);
}
+ @Override
+ public String toString() {
+ return "CarrierIdentifier{"
+ + "mcc=" + mMcc
+ + ",mnc=" + mMnc
+ + ",spn=" + mSpn
+ + ",imsi=" + mImsi
+ + ",gid1=" + mGid1
+ + ",gid2=" + mGid2
+ + "}";
+ }
+
/** @hide */
public void readFromParcel(Parcel in) {
mMcc = in.readString();
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 94ce57a..239f2d0 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -683,7 +683,7 @@
// interface.
int leftLen = mLeftIndents == null ? 0 : mLeftIndents.length;
int rightLen = mRightIndents == null ? 0 : mRightIndents.length;
- int indentsLen = Math.max(1, Math.min(leftLen, rightLen) - mLineCount);
+ int indentsLen = Math.max(1, Math.max(leftLen, rightLen) - mLineCount);
int[] indents = new int[indentsLen];
for (int i = 0; i < indentsLen; i++) {
int leftMargin = mLeftIndents == null ? 0 :
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 44b92e1..2ce43c8 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -549,8 +549,7 @@
// Compute surface insets required to draw at specified Z value.
// TODO: Use real shadow insets for a constant max Z.
if (!attrs.hasManualSurfaceInsets) {
- final int surfaceInset = (int) Math.ceil(view.getZ() * 2);
- attrs.surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset);
+ attrs.setSurfaceInsets(view, false /*manual*/, true /*preservePrevious*/);
}
CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
@@ -883,10 +882,12 @@
}
mWindowAttributes.privateFlags |= compatibleWindowFlag;
- // Restore old surface insets.
- mWindowAttributes.surfaceInsets.set(
- oldInsetLeft, oldInsetTop, oldInsetRight, oldInsetBottom);
- mWindowAttributes.hasManualSurfaceInsets = oldHasManualSurfaceInsets;
+ if (mWindowAttributes.preservePreviousSurfaceInsets) {
+ // Restore old surface insets.
+ mWindowAttributes.surfaceInsets.set(
+ oldInsetLeft, oldInsetTop, oldInsetRight, oldInsetBottom);
+ mWindowAttributes.hasManualSurfaceInsets = oldHasManualSurfaceInsets;
+ }
applyKeepScreenOnFlag(mWindowAttributes);
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 584233c..e3de810 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1482,6 +1482,16 @@
public boolean hasManualSurfaceInsets;
/**
+ * Whether the previous surface insets should be used vs. what is currently set. When set
+ * to {@code true}, the view root will ignore surfaces insets in this object and use what
+ * it currently has.
+ *
+ * @see #surfaceInsets
+ * @hide
+ */
+ public boolean preservePreviousSurfaceInsets = true;
+
+ /**
* The desired bitmap format. May be one of the constants in
* {@link android.graphics.PixelFormat}. Default is OPAQUE.
*/
@@ -1771,6 +1781,17 @@
return mTitle != null ? mTitle : "";
}
+ /**
+ * Sets the surface insets based on the elevation (visual z position) of the input view.
+ * @hide
+ */
+ public final void setSurfaceInsets(View view, boolean manual, boolean preservePrevious) {
+ final int surfaceInset = (int) Math.ceil(view.getZ() * 2);
+ surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset);
+ hasManualSurfaceInsets = manual;
+ preservePreviousSurfaceInsets = preservePrevious;
+ }
+
/** @hide */
@SystemApi
public final void setUserActivityTimeout(long timeout) {
@@ -1822,6 +1843,7 @@
out.writeInt(surfaceInsets.right);
out.writeInt(surfaceInsets.bottom);
out.writeInt(hasManualSurfaceInsets ? 1 : 0);
+ out.writeInt(preservePreviousSurfaceInsets ? 1 : 0);
out.writeInt(needsMenuKey);
out.writeInt(accessibilityIdOfAnchor);
TextUtils.writeToParcel(accessibilityTitle, out, parcelableFlags);
@@ -1874,6 +1896,7 @@
surfaceInsets.right = in.readInt();
surfaceInsets.bottom = in.readInt();
hasManualSurfaceInsets = in.readInt() != 0;
+ preservePreviousSurfaceInsets = in.readInt() != 0;
needsMenuKey = in.readInt();
accessibilityIdOfAnchor = in.readInt();
accessibilityTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
@@ -2075,6 +2098,11 @@
changes |= SURFACE_INSETS_CHANGED;
}
+ if (preservePreviousSurfaceInsets != o.preservePreviousSurfaceInsets) {
+ preservePreviousSurfaceInsets = o.preservePreviousSurfaceInsets;
+ changes |= SURFACE_INSETS_CHANGED;
+ }
+
if (needsMenuKey != o.needsMenuKey) {
needsMenuKey = o.needsMenuKey;
changes |= NEEDS_MENU_KEY_CHANGED;
@@ -2200,11 +2228,15 @@
sb.append(" userActivityTimeout=").append(userActivityTimeout);
}
if (surfaceInsets.left != 0 || surfaceInsets.top != 0 || surfaceInsets.right != 0 ||
- surfaceInsets.bottom != 0 || hasManualSurfaceInsets) {
+ surfaceInsets.bottom != 0 || hasManualSurfaceInsets
+ || !preservePreviousSurfaceInsets) {
sb.append(" surfaceInsets=").append(surfaceInsets);
if (hasManualSurfaceInsets) {
sb.append(" (manual)");
}
+ if (!preservePreviousSurfaceInsets) {
+ sb.append(" (!preservePreviousSurfaceInsets)");
+ }
}
if (needsMenuKey != NEEDS_MENU_UNSET) {
sb.append(" needsMenuKey=");
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 02d2a8b..c1076e7 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -3842,7 +3842,15 @@
*/
public static RangeInfo obtain(int type, float min, float max, float current) {
RangeInfo info = sPool.acquire();
- return (info != null) ? info : new RangeInfo(type, min, max, current);
+ if (info == null) {
+ return new RangeInfo(type, min, max, current);
+ }
+
+ info.mType = type;
+ info.mMin = min;
+ info.mMax = max;
+ info.mCurrent = current;
+ return info;
}
/**
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 0d8d8ed..af46756 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1290,9 +1290,7 @@
// We may wrap that in another view, so we'll need to manually specify
// the surface insets.
- final int surfaceInset = (int) Math.ceil(mBackgroundView.getZ() * 2);
- p.surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset);
- p.hasManualSurfaceInsets = true;
+ p.setSurfaceInsets(mBackgroundView, true /*manual*/, true /*preservePrevious*/);
mPopupViewInitialLayoutDirectionInherited =
(mContentView.getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT);
@@ -1581,7 +1579,7 @@
return true;
}
- final int spaceAbove = displayFrameTop + anchorTopInScreen - anchorHeight;
+ final int spaceAbove = anchorTopInScreen - anchorHeight - displayFrameTop;
if (height <= spaceAbove) {
// Move everything up.
if (mOverlapAnchor) {
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index e9fa26c..9c9784b 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -1347,6 +1347,13 @@
if (d instanceof LayerDrawable) {
d = ((LayerDrawable) d).findDrawableByLayerId(id);
+ if (d == null) {
+ // If we can't find the requested layer, fall back to setting
+ // the level of the entire drawable. This will break if
+ // progress is set on multiple elements, but the theme-default
+ // drawable will always have all layer IDs present.
+ d = mCurrentDrawable;
+ }
}
if (d != null) {
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 3fc02a7..085e159 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -668,12 +668,19 @@
&& mAdapter.mOrigResolveList != null) {
// Build a reasonable intent filter, based on what matched.
IntentFilter filter = new IntentFilter();
- String action = intent.getAction();
+ Intent filterIntent;
+ if (intent.getSelector() != null) {
+ filterIntent = intent.getSelector();
+ } else {
+ filterIntent = intent;
+ }
+
+ String action = filterIntent.getAction();
if (action != null) {
filter.addAction(action);
}
- Set<String> categories = intent.getCategories();
+ Set<String> categories = filterIntent.getCategories();
if (categories != null) {
for (String cat : categories) {
filter.addCategory(cat);
@@ -682,9 +689,9 @@
filter.addCategory(Intent.CATEGORY_DEFAULT);
int cat = ri.match & IntentFilter.MATCH_CATEGORY_MASK;
- Uri data = intent.getData();
+ Uri data = filterIntent.getData();
if (cat == IntentFilter.MATCH_CATEGORY_TYPE) {
- String mimeType = intent.resolveType(this);
+ String mimeType = filterIntent.resolveType(this);
if (mimeType != null) {
try {
filter.addDataType(mimeType);
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index d2ff9bc4..fe63267 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -1403,10 +1403,12 @@
@Override
public final void setElevation(float elevation) {
mElevation = elevation;
+ final WindowManager.LayoutParams attrs = getAttributes();
if (mDecor != null) {
mDecor.setElevation(elevation);
+ attrs.setSurfaceInsets(mDecor, true /*manual*/, false /*preservePrevious*/);
}
- dispatchWindowAttributesChanged(getAttributes());
+ dispatchWindowAttributesChanged(attrs);
}
@Override
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 21c4d12..b2fc2bb 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -43,4 +43,5 @@
void unregisterStrongAuthTracker(in IStrongAuthTracker tracker);
void requireStrongAuth(int strongAuthReason, int userId);
void systemReady();
+ void userPresent(int userId);
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index bceeaca..d9b6329 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -172,6 +172,14 @@
}
}
+ public void userPresent(int userId) {
+ try {
+ getLockSettings().userPresent(userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
public static final class RequestThrottledException extends Exception {
private int mTimeoutMs;
public RequestThrottledException(int timeoutMs) {
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index 6e9830e..dc9b656 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -36,7 +36,7 @@
// ----------------------------------------------------------------------------
-#define EGL_QCOM_PROTECTED_CONTENT 0x32E0
+#define EGL_PROTECTED_CONTENT_EXT 0x32C0
namespace android {
@@ -64,19 +64,12 @@
EGLDisplay dpy = eglGetCurrentDisplay();
EGLContext ctx = eglGetCurrentContext();
- if (dpy == EGL_NO_DISPLAY) {
- ALOGI("isProtectedSurface: invalid current EGLDisplay");
- return false;
- }
-
- if (ctx == EGL_NO_CONTEXT) {
- ALOGI("isProtectedSurface: invalid current EGLContext");
+ if (dpy == EGL_NO_DISPLAY || ctx == EGL_NO_CONTEXT) {
return false;
}
EGLint isProtected = EGL_FALSE;
- // TODO: Change the enum value below when an extension is ratified.
- eglQueryContext(dpy, ctx, EGL_QCOM_PROTECTED_CONTENT, &isProtected);
+ eglQueryContext(dpy, ctx, EGL_PROTECTED_CONTENT_EXT, &isProtected);
return isProtected;
}
diff --git a/core/jni/android_graphics_drawable_VectorDrawable.cpp b/core/jni/android_graphics_drawable_VectorDrawable.cpp
index 50d86ff..0de6549 100644
--- a/core/jni/android_graphics_drawable_VectorDrawable.cpp
+++ b/core/jni/android_graphics_drawable_VectorDrawable.cpp
@@ -175,7 +175,7 @@
PathParser::ParseResult result;
PathData data;
- PathParser::getPathDataFromString(&data, &result, pathString, stringLength);
+ PathParser::getPathDataFromAsciiString(&data, &result, pathString, stringLength);
if (result.failureOccurred) {
doThrowIAE(env, result.failureMessage.c_str());
}
diff --git a/core/jni/android_util_PathParser.cpp b/core/jni/android_util_PathParser.cpp
index 0c867f1..53669a8 100644
--- a/core/jni/android_util_PathParser.cpp
+++ b/core/jni/android_util_PathParser.cpp
@@ -34,7 +34,7 @@
SkPath* skPath = reinterpret_cast<SkPath*>(skPathHandle);
PathParser::ParseResult result;
- PathParser::parseStringForSkPath(skPath, &result, pathString, strLength);
+ PathParser::parseAsciiStringForSkPath(skPath, &result, pathString, strLength);
env->ReleaseStringUTFChars(inputPathStr, pathString);
if (result.failureOccurred) {
doThrowIAE(env, result.failureMessage.c_str());
@@ -56,7 +56,7 @@
const char* pathString = env->GetStringUTFChars(inputStr, NULL);
PathData* pathData = new PathData();
PathParser::ParseResult result;
- PathParser::getPathDataFromString(pathData, &result, pathString, strLength);
+ PathParser::getPathDataFromAsciiString(pathData, &result, pathString, strLength);
env->ReleaseStringUTFChars(inputStr, pathString);
if (!result.failureOccurred) {
return reinterpret_cast<jlong>(pathData);
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index fa799c9..0a99239 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4048,6 +4048,9 @@
<!-- [CHAR_LIMIT=NONE] Battery saver: Feature description -->
<string name="battery_saver_description">To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services, and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging.</string>
+ <!-- [CHAR_LIMIT=NONE] Data saver: Feature description -->
+ <string name="data_saver_description">To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them.</string>
+
<!-- Zen mode condition - summary: time duration in minutes. [CHAR LIMIT=NONE] -->
<plurals name="zen_mode_duration_minutes_summary">
<item quantity="one">For one minute (until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g>)</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e37f8d5..541ee75 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2102,6 +2102,7 @@
<java-symbol type="dimen" name="timepicker_text_size_normal" />
<java-symbol type="dimen" name="timepicker_text_size_inner" />
<java-symbol type="string" name="battery_saver_description" />
+ <java-symbol type="string" name="data_saver_description" />
<java-symbol type="string" name="zen_mode_forever" />
<java-symbol type="string" name="zen_mode_forever_dnd" />
<java-symbol type="string" name="zen_mode_rule_name_combination" />
diff --git a/graphics/java/android/graphics/PixelFormat.java b/graphics/java/android/graphics/PixelFormat.java
index 832b9c3..98082ca 100644
--- a/graphics/java/android/graphics/PixelFormat.java
+++ b/graphics/java/android/graphics/PixelFormat.java
@@ -16,8 +16,18 @@
package android.graphics;
-public class PixelFormat
-{
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+public class PixelFormat {
+
+ /** @hide */
+ @IntDef({UNKNOWN, TRANSLUCENT, TRANSPARENT, OPAQUE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Opacity {}
+
/* these constants need to match those in hardware/hardware.h */
public static final int UNKNOWN = 0;
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 4f600b4..cf5c563 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -16,7 +16,14 @@
package android.graphics.drawable;
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.annotation.AttrRes;
import android.annotation.ColorInt;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.ActivityInfo.Config;
@@ -47,17 +54,12 @@
import android.util.Xml;
import android.view.View;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.Collection;
-import com.android.internal.R;
-
/**
* A Drawable is a general abstraction for "something that can be drawn." Most
* often you will deal with Drawable as the type of resource retrieved for
@@ -148,7 +150,7 @@
*
* @param canvas The canvas to draw into
*/
- public abstract void draw(Canvas canvas);
+ public abstract void draw(@NonNull Canvas canvas);
/**
* Specify a bounding rectangle for the Drawable. This is where the drawable
@@ -176,7 +178,7 @@
* Specify a bounding rectangle for the Drawable. This is where the drawable
* will draw when its draw() method is called.
*/
- public void setBounds(Rect bounds) {
+ public void setBounds(@NonNull Rect bounds) {
setBounds(bounds.left, bounds.top, bounds.right, bounds.bottom);
}
@@ -188,7 +190,7 @@
* @param bounds Rect to receive the drawable's bounds (allocated by the
* caller).
*/
- public final void copyBounds(Rect bounds) {
+ public final void copyBounds(@NonNull Rect bounds) {
bounds.set(mBounds);
}
@@ -200,6 +202,7 @@
*
* @return A copy of the drawable's bounds
*/
+ @NonNull
public final Rect copyBounds() {
return new Rect(mBounds);
}
@@ -219,6 +222,7 @@
* @see #copyBounds()
* @see #copyBounds(android.graphics.Rect)
*/
+ @NonNull
public final Rect getBounds() {
if (mBounds == ZERO_BOUNDS_RECT) {
mBounds = new Rect();
@@ -237,6 +241,7 @@
*
* @return The dirty bounds of this drawable
*/
+ @NonNull
public Rect getDirtyBounds() {
return getBounds();
}
@@ -354,8 +359,8 @@
*
* @see #getCallback()
*/
- public final void setCallback(Callback cb) {
- mCallback = new WeakReference<Callback>(cb);
+ public final void setCallback(@Nullable Callback cb) {
+ mCallback = cb != null ? new WeakReference<>(cb) : null;
}
/**
@@ -366,11 +371,9 @@
*
* @see #setCallback(android.graphics.drawable.Drawable.Callback)
*/
+ @Nullable
public Callback getCallback() {
- if (mCallback != null) {
- return mCallback.get();
- }
- return null;
+ return mCallback != null ? mCallback.get() : null;
}
/**
@@ -399,7 +402,7 @@
*
* @see Callback#scheduleDrawable
*/
- public void scheduleSelf(Runnable what, long when) {
+ public void scheduleSelf(@NonNull Runnable what, long when) {
final Callback callback = getCallback();
if (callback != null) {
callback.scheduleDrawable(this, what, when);
@@ -415,7 +418,7 @@
*
* @see Callback#unscheduleDrawable
*/
- public void unscheduleSelf(Runnable what) {
+ public void unscheduleSelf(@NonNull Runnable what) {
final Callback callback = getCallback();
if (callback != null) {
callback.unscheduleDrawable(this, what);
@@ -429,7 +432,7 @@
* {@link android.view.View#LAYOUT_DIRECTION_RTL}
* @see #setLayoutDirection(int)
*/
- public int getLayoutDirection() {
+ public @View.ResolvedLayoutDir int getLayoutDirection() {
return mLayoutDirection;
}
@@ -441,6 +444,9 @@
* @param layoutDirection the resolved layout direction for the drawable,
* either {@link android.view.View#LAYOUT_DIRECTION_LTR}
* or {@link android.view.View#LAYOUT_DIRECTION_RTL}
+ * @return {@code true} if the layout direction change has caused the
+ * appearance of the drawable to change such that it needs to be
+ * re-drawn, {@code false} otherwise
* @see #getLayoutDirection()
*/
public final boolean setLayoutDirection(@View.ResolvedLayoutDir int layoutDirection) {
@@ -455,8 +461,9 @@
* Called when the drawable's resolved layout direction changes.
*
* @param layoutDirection the new resolved layout direction
- * @return true if the layout direction change has caused the appearance of
- * the drawable to change and it needs to be re-drawn
+ * @return {@code true} if the layout direction change has caused the
+ * appearance of the drawable to change such that it needs to be
+ * re-drawn, {@code false} otherwise
* @see #setLayoutDirection(int)
*/
public boolean onLayoutDirectionChanged(@View.ResolvedLayoutDir int layoutDirection) {
@@ -467,7 +474,7 @@
* Specify an alpha value for the drawable. 0 means fully transparent, and
* 255 means fully opaque.
*/
- public abstract void setAlpha(int alpha);
+ public abstract void setAlpha(@IntRange(from=0,to=255) int alpha);
/**
* Gets the current alpha value for the drawable. 0 means fully transparent,
@@ -476,6 +483,7 @@
* The default return value is 255 if the class does not override this method to return a value
* specific to its use of alpha.
*/
+ @IntRange(from=0,to=255)
public int getAlpha() {
return 0xFF;
}
@@ -489,7 +497,7 @@
* Drawables draw is private implementation detail, and not something apps
* should rely upon.
*/
- public void setXfermode(Xfermode mode) {
+ public void setXfermode(@Nullable Xfermode mode) {
// Base implementation drops it on the floor for compatibility. Whee!
}
@@ -592,7 +600,7 @@
*
* @return the current color filter, or {@code null} if none set
*/
- public ColorFilter getColorFilter() {
+ public @Nullable ColorFilter getColorFilter() {
return null;
}
@@ -629,7 +637,7 @@
* @param outRect the rect to populate with the hotspot bounds
* @see #setHotspotBounds(int, int, int, int)
*/
- public void getHotspotBounds(Rect outRect) {
+ public void getHotspotBounds(@NonNull Rect outRect) {
outRect.set(getBounds());
}
@@ -677,7 +685,7 @@
* of the Drawable to change (hence requiring an invalidate), otherwise
* returns false.
*/
- public boolean setState(final int[] stateSet) {
+ public boolean setState(@NonNull final int[] stateSet) {
if (!Arrays.equals(mStateSet, stateSet)) {
mStateSet = stateSet;
return onStateChange(stateSet);
@@ -692,7 +700,7 @@
* Some drawables may modify their imagery based on the selected state.
* @return An array of resource Ids describing the current state.
*/
- public int[] getState() {
+ public @NonNull int[] getState() {
return mStateSet;
}
@@ -709,7 +717,7 @@
* {@link StateListDrawable} and {@link LevelListDrawable} this will be the child drawable
* currently in use.
*/
- public Drawable getCurrent() {
+ public @NonNull Drawable getCurrent() {
return this;
}
@@ -729,7 +737,7 @@
* of the Drawable to change (hence requiring an invalidate), otherwise
* returns false.
*/
- public final boolean setLevel(int level) {
+ public final boolean setLevel(@IntRange(from=0,to=10000) int level) {
if (mLevel != level) {
mLevel = level;
return onLevelChange(level);
@@ -742,7 +750,7 @@
*
* @return int Current level, from 0 (minimum) to 10000 (maximum).
*/
- public final int getLevel() {
+ public final @IntRange(from=0,to=10000) int getLevel() {
return mLevel;
}
@@ -839,7 +847,7 @@
*
* @see android.graphics.PixelFormat
*/
- public abstract int getOpacity();
+ public abstract @PixelFormat.Opacity int getOpacity();
/**
* Return the appropriate opacity value for two source opacities. If
@@ -856,7 +864,8 @@
*
* @see #getOpacity
*/
- public static int resolveOpacity(int op1, int op2) {
+ public static @PixelFormat.Opacity int resolveOpacity(@PixelFormat.Opacity int op1,
+ @PixelFormat.Opacity int op2) {
if (op1 == op2) {
return op1;
}
@@ -885,7 +894,7 @@
* report, else a Region holding the parts of the Drawable's bounds that
* are transparent.
*/
- public Region getTransparentRegion() {
+ public @Nullable Region getTransparentRegion() {
return null;
}
@@ -898,7 +907,10 @@
* if it looks the same and there is no need to redraw it since its
* last state.
*/
- protected boolean onStateChange(int[] state) { return false; }
+ protected boolean onStateChange(int[] state) {
+ return false;
+ }
+
/** Override this in your subclass to change appearance if you vary based
* on level.
* @return Returns true if the level change has caused the appearance of
@@ -906,12 +918,17 @@
* if it looks the same and there is no need to redraw it since its
* last level.
*/
- protected boolean onLevelChange(int level) { return false; }
+ protected boolean onLevelChange(int level) {
+ return false;
+ }
+
/**
* Override this in your subclass to change appearance if you vary based on
* the bounds.
*/
- protected void onBoundsChange(Rect bounds) {}
+ protected void onBoundsChange(Rect bounds) {
+ // Stub method.
+ }
/**
* Returns the drawable's intrinsic width.
@@ -986,7 +1003,7 @@
*
* @hide
*/
- public Insets getOpticalInsets() {
+ public @NonNull Insets getOpticalInsets() {
return Insets.NONE;
}
@@ -1020,7 +1037,7 @@
* @see ConstantState
* @see #getConstantState()
*/
- public Drawable mutate() {
+ public @NonNull Drawable mutate() {
return this;
}
@@ -1126,9 +1143,10 @@
AttributeSet attrs = Xml.asAttributeSet(parser);
int type;
- while ((type=parser.next()) != XmlPullParser.START_TAG &&
- type != XmlPullParser.END_DOCUMENT) {
- // Empty loop
+ //noinspection StatementWithEmptyBody
+ while ((type=parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ // Empty loop.
}
if (type != XmlPullParser.START_TAG) {
@@ -1222,8 +1240,9 @@
* @throws XmlPullParserException
* @throws IOException
*/
- void inflateWithAttributes(@NonNull Resources r, @NonNull XmlPullParser parser,
- @NonNull TypedArray attrs, int visibleAttr) throws XmlPullParserException, IOException {
+ void inflateWithAttributes(@NonNull @SuppressWarnings("unused") Resources r,
+ @NonNull @SuppressWarnings("unused") XmlPullParser parser, @NonNull TypedArray attrs,
+ @AttrRes int visibleAttr) throws XmlPullParserException, IOException {
mVisible = attrs.getBoolean(visibleAttr, mVisible);
}
@@ -1254,8 +1273,7 @@
* @return a new drawable object based on this constant state
* @see {@link #newDrawable(Resources)}
*/
- @NonNull
- public abstract Drawable newDrawable();
+ public abstract @NonNull Drawable newDrawable();
/**
* Creates a new Drawable instance from its constant state using the
@@ -1269,8 +1287,7 @@
* be displayed
* @return a new drawable object based on this constant state
*/
- @NonNull
- public Drawable newDrawable(@Nullable Resources res) {
+ public @NonNull Drawable newDrawable(@Nullable Resources res) {
return newDrawable();
}
@@ -1288,8 +1305,8 @@
* displayed
* @return a new drawable object based on this constant state
*/
- @NonNull
- public Drawable newDrawable(@Nullable Resources res, @Nullable Theme theme) {
+ public @NonNull Drawable newDrawable(@Nullable Resources res,
+ @Nullable @SuppressWarnings("unused") Theme theme) {
return newDrawable(res);
}
@@ -1303,12 +1320,12 @@
* @return Total pixel count
* @hide
*/
- public int addAtlasableBitmaps(Collection<Bitmap> atlasList) {
+ public int addAtlasableBitmaps(@NonNull Collection<Bitmap> atlasList) {
return 0;
}
/** @hide */
- protected final boolean isAtlasable(Bitmap bitmap) {
+ protected final boolean isAtlasable(@Nullable Bitmap bitmap) {
return bitmap != null && bitmap.getConfig() == Bitmap.Config.ARGB_8888;
}
@@ -1327,7 +1344,7 @@
* @see ConstantState
* @see Drawable#mutate()
*/
- public ConstantState getConstantState() {
+ public @Nullable ConstantState getConstantState() {
return null;
}
@@ -1345,8 +1362,8 @@
* Ensures the tint filter is consistent with the current tint color and
* mode.
*/
- PorterDuffColorFilter updateTintFilter(PorterDuffColorFilter tintFilter, ColorStateList tint,
- PorterDuff.Mode tintMode) {
+ @Nullable PorterDuffColorFilter updateTintFilter(@Nullable PorterDuffColorFilter tintFilter,
+ @Nullable ColorStateList tint, @Nullable PorterDuff.Mode tintMode) {
if (tint == null || tintMode == null) {
return null;
}
@@ -1365,8 +1382,8 @@
* Obtains styled attributes from the theme, if available, or unstyled
* resources if the theme is null.
*/
- static TypedArray obtainAttributes(
- Resources res, Theme theme, AttributeSet set, int[] attrs) {
+ static @NonNull TypedArray obtainAttributes(@NonNull Resources res, @Nullable Theme theme,
+ @NonNull AttributeSet set, @NonNull int[] attrs) {
if (theme == null) {
return res.obtainAttributes(set, attrs);
}
@@ -1418,8 +1435,6 @@
final int rounded = Math.round(result);
if (rounded != 0) {
return rounded;
- } else if (pixels == 0) {
- return 0;
} else if (pixels > 0) {
return 1;
} else {
@@ -1440,7 +1455,7 @@
* @param cause the exception to re-throw
* @throws RuntimeException
*/
- static void rethrowAsRuntimeException(Exception cause) throws RuntimeException {
+ static void rethrowAsRuntimeException(@NonNull Exception cause) throws RuntimeException {
final RuntimeException e = new RuntimeException(cause);
e.setStackTrace(new StackTraceElement[0]);
throw e;
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 6913f43..715c875 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -34,9 +34,7 @@
#include <utils/String8.h>
#include <utils/threads.h>
#include <utils/Timers.h>
-#ifdef __ANDROID__
-#include <cutils/trace.h>
-#endif
+#include <utils/Trace.h>
#include <assert.h>
#include <dirent.h>
@@ -54,14 +52,6 @@
_rc; })
#endif
-#ifdef __ANDROID__
-#define MY_TRACE_BEGIN(x) ATRACE_BEGIN(x)
-#define MY_TRACE_END() ATRACE_END()
-#else
-#define MY_TRACE_BEGIN(x)
-#define MY_TRACE_END()
-#endif
-
using namespace android;
static const bool kIsDebug = false;
@@ -623,7 +613,7 @@
ResTable* sharedRes = NULL;
bool shared = true;
bool onlyEmptyResources = true;
- MY_TRACE_BEGIN(ap.path.string());
+ ATRACE_NAME(ap.path.string());
Asset* idmap = openIdmapLocked(ap);
size_t nextEntryIdx = mResources->getTableCount();
ALOGV("Looking for resource asset in '%s'\n", ap.path.string());
@@ -703,8 +693,6 @@
if (idmap != NULL) {
delete idmap;
}
- MY_TRACE_END();
-
return onlyEmptyResources;
}
@@ -752,6 +740,7 @@
void AssetManager::updateResourceParamsLocked() const
{
+ ATRACE_CALL();
ResTable* res = mResources;
if (!res) {
return;
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 1ccc59a..15cb684 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -24,6 +24,7 @@
#include <stdlib.h>
#include <string.h>
+#include <algorithm>
#include <limits>
#include <memory>
#include <type_traits>
@@ -5810,6 +5811,10 @@
return NULL;
}
+static bool compareResTableConfig(const ResTable_config& a, const ResTable_config& b) {
+ return a.compare(b) < 0;
+}
+
void ResTable::getConfigurations(Vector<ResTable_config>* configs, bool ignoreMipmap,
bool ignoreAndroidPackage, bool includeSystemConfigs) const {
const size_t packageCount = mPackageGroups.size();
@@ -5840,17 +5845,11 @@
ResTable_config cfg;
memset(&cfg, 0, sizeof(ResTable_config));
cfg.copyFromDtoH(config->config);
- // only insert unique
- const size_t N = configs->size();
- size_t n;
- for (n = 0; n < N; n++) {
- if (0 == (*configs)[n].compare(cfg)) {
- break;
- }
- }
- // if we didn't find it
- if (n == N) {
- configs->add(cfg);
+
+ auto iter = std::lower_bound(configs->begin(), configs->end(), cfg,
+ compareResTableConfig);
+ if (iter == configs->end() || iter->compare(cfg) != 0) {
+ configs->insertAt(cfg, std::distance(configs->begin(), iter));
}
}
}
@@ -5858,6 +5857,10 @@
}
}
+static bool compareString8AndCString(const String8& str, const char* cStr) {
+ return strcmp(str.string(), cStr) < 0;
+}
+
void ResTable::getLocales(Vector<String8>* locales, bool includeSystemLocales) const
{
Vector<ResTable_config> configs;
@@ -5872,15 +5875,11 @@
char locale[RESTABLE_MAX_LOCALE_LEN];
for (size_t i=0; i<I; i++) {
configs[i].getBcp47Locale(locale);
- const size_t J = locales->size();
- size_t j;
- for (j=0; j<J; j++) {
- if (0 == strcmp(locale, (*locales)[j].string())) {
- break;
- }
- }
- if (j == J) {
- locales->add(String8(locale));
+
+ auto iter = std::lower_bound(locales->begin(), locales->end(), locale,
+ compareString8AndCString);
+ if (iter == locales->end() || strcmp(iter->string(), locale) != 0) {
+ locales->insertAt(String8(locale), std::distance(locales->begin(), iter));
}
}
}
diff --git a/libs/androidfw/tests/ResTable_test.cpp b/libs/androidfw/tests/ResTable_test.cpp
index 7cd7fb5..b8b4625 100644
--- a/libs/androidfw/tests/ResTable_test.cpp
+++ b/libs/androidfw/tests/ResTable_test.cpp
@@ -39,8 +39,20 @@
*/
#include "data/basic/basic_arsc.h"
+/**
+ * Include a binary library resource table.
+ *
+ * Package: com.android.test.basic
+ */
#include "data/lib/lib_arsc.h"
+/**
+ * Include a system resource table.
+ *
+ * Package: android
+ */
+#include "data/system/system_arsc.h"
+
TEST(ResTableTest, shouldLoadSuccessfully) {
ResTable table;
ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
@@ -324,4 +336,25 @@
ASSERT_EQ(uint32_t(600), val.data);
}
+TEST(ResTableTest, GetConfigurationsReturnsUniqueList) {
+ ResTable table;
+ ASSERT_EQ(NO_ERROR, table.add(system_arsc, system_arsc_len));
+ ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
+
+ ResTable_config configSv;
+ memset(&configSv, 0, sizeof(configSv));
+ configSv.language[0] = 's';
+ configSv.language[1] = 'v';
+
+ Vector<ResTable_config> configs;
+ table.getConfigurations(&configs);
+
+ EXPECT_EQ(1, std::count(configs.begin(), configs.end(), configSv));
+
+ Vector<String8> locales;
+ table.getLocales(&locales);
+
+ EXPECT_EQ(1, std::count(locales.begin(), locales.end(), String8("sv")));
+}
+
} // namespace
diff --git a/libs/androidfw/tests/TestHelpers.h b/libs/androidfw/tests/TestHelpers.h
index ac80d88..ff9be16 100644
--- a/libs/androidfw/tests/TestHelpers.h
+++ b/libs/androidfw/tests/TestHelpers.h
@@ -21,7 +21,7 @@
enum { MAY_NOT_BE_BAG = false };
static inline bool operator==(const android::ResTable_config& a, const android::ResTable_config& b) {
- return memcmp(&a, &b, sizeof(a)) == 0;
+ return a.compare(b) == 0;
}
static inline ::std::ostream& operator<<(::std::ostream& out, const android::ResTable_config& c) {
diff --git a/libs/androidfw/tests/data/system/R.h b/libs/androidfw/tests/data/system/R.h
index 27f25fe..6a31fb8 100644
--- a/libs/androidfw/tests/data/system/R.h
+++ b/libs/androidfw/tests/data/system/R.h
@@ -33,6 +33,12 @@
};
}
+namespace integer {
+ enum {
+ number = 0x01030000, // sv
+ };
+}
+
} // namespace R
} // namespace android
diff --git a/libs/androidfw/tests/data/system/res/values-sv/values.xml b/libs/androidfw/tests/data/system/res/values-sv/values.xml
new file mode 100644
index 0000000..b97bdb6
--- /dev/null
+++ b/libs/androidfw/tests/data/system/res/values-sv/values.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <public type="integer" name="number" id="0x01030000" />
+ <integer name="number">1</integer>
+</resources>
diff --git a/libs/androidfw/tests/data/system/system_arsc.h b/libs/androidfw/tests/data/system/system_arsc.h
index 215ecae..b0dab6b 100644
--- a/libs/androidfw/tests/data/system/system_arsc.h
+++ b/libs/androidfw/tests/data/system/system_arsc.h
@@ -1,8 +1,8 @@
unsigned char system_arsc[] = {
- 0x02, 0x00, 0x0c, 0x00, 0x18, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x0c, 0x00, 0xf8, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xf0, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xd0, 0x03, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00,
0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -25,26 +25,33 @@
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x40, 0x00, 0x00, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00,
- 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00,
- 0x6c, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00,
- 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x98, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x78, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00, 0x6c, 0x00, 0x65, 0x00,
+ 0x00, 0x00, 0x07, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00,
+ 0x67, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x5e, 0x00,
+ 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x2d, 0x00, 0x70, 0x00,
+ 0x72, 0x00, 0x69, 0x00, 0x76, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x84, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00,
0x0a, 0x00, 0x62, 0x00, 0x61, 0x00, 0x63, 0x00, 0x6b, 0x00, 0x67, 0x00,
0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x00, 0x00,
0x0a, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x65, 0x00, 0x67, 0x00,
0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x00, 0x00,
0x09, 0x00, 0x54, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00,
- 0x2e, 0x00, 0x4f, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40,
- 0x01, 0x02, 0x44, 0x00, 0x84, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+ 0x2e, 0x00, 0x4f, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x06, 0x00,
+ 0x6e, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
+ 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x4c, 0x00, 0x8c, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
+ 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -55,15 +62,27 @@
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00,
0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x44, 0x00,
- 0x70, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x4c, 0x00,
+ 0x78, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x50, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0xff, 0xff,
- 0x01, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xff
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
+ 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x01, 0x01,
+ 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xff, 0x02, 0x02, 0x10, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x4c, 0x00, 0x60, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
+ 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x76, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10,
+ 0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
-unsigned int system_arsc_len = 792;
+unsigned int system_arsc_len = 1016;
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index bd71e0d..4d65782 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -226,7 +226,7 @@
// Set to 0 so that the animate() basically instantly finishes
mStartTime = 0;
}
- if (mDuration < 0 || mDuration > 50000) {
+ if (mDuration < 0) {
ALOGW("Your duration is strange and confusing: %" PRId64, mDuration);
}
}
diff --git a/libs/hwui/PathParser.cpp b/libs/hwui/PathParser.cpp
index 7e85333..2179f14 100644
--- a/libs/hwui/PathParser.cpp
+++ b/libs/hwui/PathParser.cpp
@@ -162,7 +162,7 @@
|| verb == 's' || verb == 't' || verb == 'v' || verb == 'z';
}
-void PathParser::getPathDataFromString(PathData* data, ParseResult* result,
+void PathParser::getPathDataFromAsciiString(PathData* data, ParseResult* result,
const char* pathStr, size_t strLen) {
if (pathStr == NULL) {
result->failureOccurred = true;
@@ -171,7 +171,16 @@
}
size_t start = 0;
- size_t end = 1;
+ // Skip leading spaces.
+ while (isspace(pathStr[start]) && start < strLen) {
+ start++;
+ }
+ if (start == strLen) {
+ result->failureOccurred = true;
+ result->failureMessage = "Path string cannot be empty.";
+ return;
+ }
+ size_t end = start + 1;
while (end < strLen) {
end = nextStart(pathStr, strLen, end);
@@ -226,9 +235,9 @@
ALOGD("points are : %s", os.str().c_str());
}
-void PathParser::parseStringForSkPath(SkPath* skPath, ParseResult* result, const char* pathStr, size_t strLen) {
+void PathParser::parseAsciiStringForSkPath(SkPath* skPath, ParseResult* result, const char* pathStr, size_t strLen) {
PathData pathData;
- getPathDataFromString(&pathData, result, pathStr, strLen);
+ getPathDataFromAsciiString(&pathData, result, pathStr, strLen);
if (result->failureOccurred) {
return;
}
diff --git a/libs/hwui/PathParser.h b/libs/hwui/PathParser.h
index 180a7a3..5578e8d 100644
--- a/libs/hwui/PathParser.h
+++ b/libs/hwui/PathParser.h
@@ -39,9 +39,9 @@
/**
* Parse the string literal and create a Skia Path. Return true on success.
*/
- ANDROID_API static void parseStringForSkPath(SkPath* outPath, ParseResult* result,
+ ANDROID_API static void parseAsciiStringForSkPath(SkPath* outPath, ParseResult* result,
const char* pathStr, size_t strLength);
- ANDROID_API static void getPathDataFromString(PathData* outData, ParseResult* result,
+ ANDROID_API static void getPathDataFromAsciiString(PathData* outData, ParseResult* result,
const char* pathStr, size_t strLength);
static void dump(const PathData& data);
static bool isVerbValid(char verb);
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index adfe45c..ac17ed2 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -96,7 +96,7 @@
Path::Path(const char* pathStr, size_t strLength) {
PathParser::ParseResult result;
Data data;
- PathParser::getPathDataFromString(&data, &result, pathStr, strLength);
+ PathParser::getPathDataFromAsciiString(&data, &result, pathStr, strLength);
mStagingProperties.setData(data);
}
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index e4c7ed7..691cfa01 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -40,11 +40,11 @@
namespace uirenderer {
namespace VectorDrawable {
-#define VD_SET_PROP_WITH_FLAG(field, value, flag) (VD_SET_PROP_AND_NOTIFY(field, value) ? (flag = true, true) : false)
-#define VD_SET_PROP(field, value) (value != field ? (field = value, true) : false)
-#define VD_SET_PROP_AND_NOTIFY(field, value) ({ bool retVal = VD_SET_PROP(field, value);\
+#define VD_SET_PRIMITIVE_FIELD_WITH_FLAG(field, value, flag) (VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, (value)) ? ((flag) = true, true) : false)
+#define VD_SET_PROP(field, value) ((value) != (field) ? ((field) = (value), true) : false)
+#define VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, value) ({ bool retVal = VD_SET_PROP((mPrimitiveFields.field), (value));\
onPropertyChanged(); retVal;})
-#define UPDATE_SKPROP(field, value) ({bool retVal = (field != value); if (field != value) SkRefCnt_SafeAssign(field, value); retVal;})
+#define UPDATE_SKPROP(field, value) ({bool retVal = ((field) != (value)); if ((field) != (value)) SkRefCnt_SafeAssign((field), (value)); retVal;})
/* A VectorDrawable is composed of a tree of nodes.
* Each node can be a group node, or a path.
@@ -248,49 +248,49 @@
return mPrimitiveFields.strokeWidth;
}
void setStrokeWidth(float strokeWidth) {
- VD_SET_PROP_AND_NOTIFY(strokeWidth, strokeWidth);
+ VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeWidth, strokeWidth);
}
SkColor getStrokeColor() const{
return mPrimitiveFields.strokeColor;
}
void setStrokeColor(SkColor strokeColor) {
- VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.strokeColor, strokeColor);
+ VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeColor, strokeColor);
}
float getStrokeAlpha() const{
return mPrimitiveFields.strokeAlpha;
}
void setStrokeAlpha(float strokeAlpha) {
- VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.strokeAlpha, strokeAlpha);
+ VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeAlpha, strokeAlpha);
}
SkColor getFillColor() const {
return mPrimitiveFields.fillColor;
}
void setFillColor(SkColor fillColor) {
- VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.fillColor, fillColor);
+ VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillColor, fillColor);
}
float getFillAlpha() const{
return mPrimitiveFields.fillAlpha;
}
void setFillAlpha(float fillAlpha) {
- VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.fillAlpha, fillAlpha);
+ VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillAlpha, fillAlpha);
}
float getTrimPathStart() const{
return mPrimitiveFields.trimPathStart;
}
void setTrimPathStart(float trimPathStart) {
- VD_SET_PROP_WITH_FLAG(mPrimitiveFields.trimPathStart, trimPathStart, mTrimDirty);
+ VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathStart, trimPathStart, mTrimDirty);
}
float getTrimPathEnd() const{
return mPrimitiveFields.trimPathEnd;
}
void setTrimPathEnd(float trimPathEnd) {
- VD_SET_PROP_WITH_FLAG(mPrimitiveFields.trimPathEnd, trimPathEnd, mTrimDirty);
+ VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathEnd, trimPathEnd, mTrimDirty);
}
float getTrimPathOffset() const{
return mPrimitiveFields.trimPathOffset;
}
void setTrimPathOffset(float trimPathOffset) {
- VD_SET_PROP_WITH_FLAG(mPrimitiveFields.trimPathOffset, trimPathOffset, mTrimDirty);
+ VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathOffset, trimPathOffset, mTrimDirty);
}
float getStrokeMiterLimit() const {
@@ -425,43 +425,43 @@
return mPrimitiveFields.rotate;
}
void setRotation(float rotation) {
- VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.rotate, rotation);
+ VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(rotate, rotation);
}
float getPivotX() const {
return mPrimitiveFields.pivotX;
}
void setPivotX(float pivotX) {
- VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.pivotX, pivotX);
+ VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotX, pivotX);
}
float getPivotY() const {
return mPrimitiveFields.pivotY;
}
void setPivotY(float pivotY) {
- VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.pivotY, pivotY);
+ VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotY, pivotY);
}
float getScaleX() const {
return mPrimitiveFields.scaleX;
}
void setScaleX(float scaleX) {
- VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.scaleX, scaleX);
+ VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleX, scaleX);
}
float getScaleY() const {
return mPrimitiveFields.scaleY;
}
void setScaleY(float scaleY) {
- VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.scaleY, scaleY);
+ VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleY, scaleY);
}
float getTranslateX() const {
return mPrimitiveFields.translateX;
}
void setTranslateX(float translateX) {
- VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.translateX, translateX);
+ VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateX, translateX);
}
float getTranslateY() const {
return mPrimitiveFields.translateY;
}
void setTranslateY(float translateY) {
- VD_SET_PROP_AND_NOTIFY(translateY, translateY);
+ VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateY, translateY);
}
void updateProperties(float rotate, float pivotX, float pivotY,
float scaleX, float scaleY, float translateX, float translateY) {
diff --git a/libs/hwui/tests/microbench/PathParserBench.cpp b/libs/hwui/tests/microbench/PathParserBench.cpp
index 4186539..b43c4c3 100644
--- a/libs/hwui/tests/microbench/PathParserBench.cpp
+++ b/libs/hwui/tests/microbench/PathParserBench.cpp
@@ -31,7 +31,7 @@
size_t length = strlen(sPathString);
PathParser::ParseResult result;
while (state.KeepRunning()) {
- PathParser::parseStringForSkPath(&skPath, &result, sPathString, length);
+ PathParser::parseAsciiStringForSkPath(&skPath, &result, sPathString, length);
benchmark::DoNotOptimize(&result);
benchmark::DoNotOptimize(&skPath);
}
@@ -43,7 +43,7 @@
PathData outData;
PathParser::ParseResult result;
while (state.KeepRunning()) {
- PathParser::getPathDataFromString(&outData, &result, sPathString, length);
+ PathParser::getPathDataFromAsciiString(&outData, &result, sPathString, length);
benchmark::DoNotOptimize(&result);
benchmark::DoNotOptimize(&outData);
}
diff --git a/libs/hwui/tests/unit/VectorDrawableTests.cpp b/libs/hwui/tests/unit/VectorDrawableTests.cpp
index 796169e..83b485f 100644
--- a/libs/hwui/tests/unit/VectorDrawableTests.cpp
+++ b/libs/hwui/tests/unit/VectorDrawableTests.cpp
@@ -234,9 +234,10 @@
{"3e...3", false}, // Not starting with a verb and ill-formatted float
{"L.M.F.A.O", false}, // No floats following verbs
{"m 1 1", true}, // Valid path data
- {"z", true}, // Valid path data
+ {"\n \t z", true}, // Valid path data with leading spaces
{"1-2e34567", false}, // Not starting with a verb and ill-formatted float
- {"f 4 5", false} // Invalid verb
+ {"f 4 5", false}, // Invalid verb
+ {"\r ", false} // Empty string
};
@@ -250,7 +251,7 @@
// Test generated path data against the given data.
PathData pathData;
size_t length = strlen(testData.pathString);
- PathParser::getPathDataFromString(&pathData, &result, testData.pathString, length);
+ PathParser::getPathDataFromAsciiString(&pathData, &result, testData.pathString, length);
EXPECT_EQ(testData.pathData, pathData);
}
@@ -258,7 +259,7 @@
PathParser::ParseResult result;
PathData pathData;
SkPath skPath;
- PathParser::getPathDataFromString(&pathData, &result,
+ PathParser::getPathDataFromAsciiString(&pathData, &result,
stringPath.stringPath, strlen(stringPath.stringPath));
EXPECT_EQ(stringPath.isValid, !result.failureOccurred);
}
@@ -274,13 +275,13 @@
}
}
-TEST(PathParser, parseStringForSkPath) {
+TEST(PathParser, parseAsciiStringForSkPath) {
for (TestData testData: sTestDataSet) {
PathParser::ParseResult result;
size_t length = strlen(testData.pathString);
// Check the return value as well as the SkPath generated.
SkPath actualPath;
- PathParser::parseStringForSkPath(&actualPath, &result, testData.pathString, length);
+ PathParser::parseAsciiStringForSkPath(&actualPath, &result, testData.pathString, length);
bool hasValidData = !result.failureOccurred;
EXPECT_EQ(hasValidData, testData.pathData.verbs.size() > 0);
SkPath expectedPath;
@@ -291,7 +292,7 @@
for (StringPath stringPath : sStringPaths) {
PathParser::ParseResult result;
SkPath skPath;
- PathParser::parseStringForSkPath(&skPath, &result, stringPath.stringPath,
+ PathParser::parseAsciiStringForSkPath(&skPath, &result, stringPath.stringPath,
strlen(stringPath.stringPath));
EXPECT_EQ(stringPath.isValid, !result.failureOccurred);
}
@@ -390,5 +391,40 @@
EXPECT_EQ(matrixAndScale.matrixScale, actualMatrixScale);
}
}
+
+TEST(VectorDrawable, groupProperties) {
+ //TODO: Also need to test property sync and dirty flag when properties change.
+ VectorDrawable::Group group;
+ VectorDrawable::Group::GroupProperties* properties = group.mutateProperties();
+ // Test default values, change values through setters and verify the change through getters.
+ EXPECT_EQ(0.0f, properties->getTranslateX());
+ properties->setTranslateX(1.0f);
+ EXPECT_EQ(1.0f, properties->getTranslateX());
+
+ EXPECT_EQ(0.0f, properties->getTranslateY());
+ properties->setTranslateY(1.0f);
+ EXPECT_EQ(1.0f, properties->getTranslateY());
+
+ EXPECT_EQ(0.0f, properties->getRotation());
+ properties->setRotation(1.0f);
+ EXPECT_EQ(1.0f, properties->getRotation());
+
+ EXPECT_EQ(1.0f, properties->getScaleX());
+ properties->setScaleX(0.0f);
+ EXPECT_EQ(0.0f, properties->getScaleX());
+
+ EXPECT_EQ(1.0f, properties->getScaleY());
+ properties->setScaleY(0.0f);
+ EXPECT_EQ(0.0f, properties->getScaleY());
+
+ EXPECT_EQ(0.0f, properties->getPivotX());
+ properties->setPivotX(1.0f);
+ EXPECT_EQ(1.0f, properties->getPivotX());
+
+ EXPECT_EQ(0.0f, properties->getPivotY());
+ properties->setPivotY(1.0f);
+ EXPECT_EQ(1.0f, properties->getPivotY());
+
+}
}; // namespace uirenderer
}; // namespace android
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index 0b64876..a33b219 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -16,7 +16,9 @@
package android.media.tv;
+import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.StringRes;
import android.annotation.SystemApi;
import android.content.ComponentName;
import android.content.Context;
@@ -48,6 +50,8 @@
import java.io.IOException;
import java.io.InputStream;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
@@ -62,6 +66,12 @@
private static final boolean DEBUG = false;
private static final String TAG = "TvInputInfo";
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({TYPE_TUNER, TYPE_OTHER, TYPE_COMPOSITE, TYPE_SVIDEO, TYPE_SCART, TYPE_COMPONENT,
+ TYPE_VGA, TYPE_DVI, TYPE_HDMI, TYPE_DISPLAY_PORT})
+ public @interface Type {}
+
// Should be in sync with frameworks/base/core/res/res/values/attrs.xml
/**
* TV input type: the TV input service is a tuner which provides channels.
@@ -343,6 +353,7 @@
/**
* Returns the type of this TV input.
*/
+ @Type
public int getType() {
return mType;
}
@@ -768,7 +779,7 @@
* @hide
*/
@SystemApi
- public Builder setLabel(int resId) {
+ public Builder setLabel(@StringRes int resId) {
if (mLabel != null) {
throw new IllegalStateException("Label text is already set.");
}
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index b4536b1..d74dda6 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -99,6 +99,13 @@
*/
public static final int DVB_DEVICE_FRONTEND = DVB_DEVICE_END;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({VIDEO_UNAVAILABLE_REASON_UNKNOWN, VIDEO_UNAVAILABLE_REASON_TUNING,
+ VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL, VIDEO_UNAVAILABLE_REASON_BUFFERING,
+ VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY})
+ public @interface VideoUnavailableReason {}
+
static final int VIDEO_UNAVAILABLE_REASON_START = 0;
static final int VIDEO_UNAVAILABLE_REASON_END = 4;
@@ -135,10 +142,9 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({VIDEO_UNAVAILABLE_REASON_UNKNOWN, VIDEO_UNAVAILABLE_REASON_TUNING,
- VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL, VIDEO_UNAVAILABLE_REASON_BUFFERING,
- VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY})
- public @interface VideoUnavailableReason {}
+ @IntDef({TIME_SHIFT_STATUS_UNKNOWN, TIME_SHIFT_STATUS_UNSUPPORTED,
+ TIME_SHIFT_STATUS_UNAVAILABLE, TIME_SHIFT_STATUS_AVAILABLE})
+ public @interface TimeShiftStatus {}
/**
* Status for {@link TvInputService.Session#notifyTimeShiftStatusChanged(int)} and
@@ -169,12 +175,6 @@
*/
public static final int TIME_SHIFT_STATUS_AVAILABLE = 3;
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({TIME_SHIFT_STATUS_UNKNOWN, TIME_SHIFT_STATUS_UNSUPPORTED,
- TIME_SHIFT_STATUS_UNAVAILABLE, TIME_SHIFT_STATUS_AVAILABLE})
- public @interface TimeShiftStatus {}
-
/**
* Value returned by {@link TvInputService.Session#onTimeShiftGetCurrentPosition()} and
* {@link TvInputService.Session#onTimeShiftGetStartPosition()} when time shifting has not
@@ -182,6 +182,12 @@
*/
public static final long TIME_SHIFT_INVALID_TIME = Long.MIN_VALUE;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({RECORDING_ERROR_UNKNOWN, RECORDING_ERROR_INSUFFICIENT_SPACE,
+ RECORDING_ERROR_RESOURCE_BUSY})
+ public @interface RecordingError {}
+
/**
* Error for {@link TvInputService.RecordingSession#notifyError(int)} and
* {@link TvRecordingClient.RecordingCallback#onError(int)}: The requested operation cannot be
@@ -205,9 +211,8 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef({RECORDING_ERROR_UNKNOWN, RECORDING_ERROR_INSUFFICIENT_SPACE,
- RECORDING_ERROR_RESOURCE_BUSY})
- public @interface RecordingError {}
+ @IntDef({INPUT_STATE_CONNECTED, INPUT_STATE_CONNECTED_STANDBY, INPUT_STATE_DISCONNECTED})
+ public @interface InputState {}
/**
* State for {@link #getInputState(String)} and
@@ -240,11 +245,6 @@
*/
public static final int INPUT_STATE_DISCONNECTED = 2;
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({INPUT_STATE_CONNECTED, INPUT_STATE_CONNECTED_STANDBY, INPUT_STATE_DISCONNECTED})
- public @interface InputState {}
-
/**
* Broadcast intent action when the user blocked content ratings change. For use with the
* {@link #isRatingBlocked}.
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 97ef6d8..3780f6f 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -16,6 +16,7 @@
package android.media.tv;
+import android.annotation.FloatRange;
import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -823,7 +824,7 @@
*
* @param volume A volume value between {@code 0.0f} to {@code 1.0f}.
*/
- public abstract void onSetStreamVolume(float volume);
+ public abstract void onSetStreamVolume(@FloatRange(from = 0.0, to = 1.0) float volume);
/**
* Tunes to a given channel.
diff --git a/media/java/android/media/tv/TvTrackInfo.java b/media/java/android/media/tv/TvTrackInfo.java
index d718a7e..c9c881c 100644
--- a/media/java/android/media/tv/TvTrackInfo.java
+++ b/media/java/android/media/tv/TvTrackInfo.java
@@ -16,6 +16,7 @@
package android.media.tv;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.os.Bundle;
import android.os.Parcel;
@@ -24,12 +25,20 @@
import com.android.internal.util.Preconditions;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
/**
* Encapsulates the format of tracks played in {@link TvInputService}.
*/
public final class TvTrackInfo implements Parcelable {
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({TYPE_AUDIO, TYPE_VIDEO, TYPE_SUBTITLE})
+ public @interface Type {}
+
/**
* The type value for audio tracks.
*/
@@ -96,6 +105,7 @@
* Returns the type of the track. The type should be one of the followings:
* {@link #TYPE_AUDIO}, {@link #TYPE_VIDEO} and {@link #TYPE_SUBTITLE}.
*/
+ @Type
public final int getType() {
return mType;
}
@@ -319,7 +329,7 @@
* @throws IllegalArgumentException if the type is not any of {@link #TYPE_AUDIO},
* {@link #TYPE_VIDEO} and {@link #TYPE_SUBTITLE}
*/
- public Builder(int type, @NonNull String id) {
+ public Builder(@Type int type, @NonNull String id) {
if (type != TYPE_AUDIO
&& type != TYPE_VIDEO
&& type != TYPE_SUBTITLE) {
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index 02ee0cc..71b0193 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -16,6 +16,7 @@
package android.media.tv;
+import android.annotation.FloatRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -271,7 +272,7 @@
*
* @param volume A volume value between {@code 0.0f} to {@code 1.0f}.
*/
- public void setStreamVolume(float volume) {
+ public void setStreamVolume(@FloatRange(from = 0.0, to = 1.0) float volume) {
if (DEBUG) Log.d(TAG, "setStreamVolume(" + volume + ")");
mStreamVolume = volume;
if (mSession == null) {
diff --git a/media/jni/soundpool/SoundPoolThread.h b/media/jni/soundpool/SoundPoolThread.h
index d388388..9096aeb 100644
--- a/media/jni/soundpool/SoundPoolThread.h
+++ b/media/jni/soundpool/SoundPoolThread.h
@@ -47,7 +47,7 @@
void write(SoundPoolMsg msg);
private:
- static const size_t maxMessages = 5;
+ static const size_t maxMessages = 128;
static int beginThread(void* arg);
int run();
diff --git a/packages/DocumentsUI/Android.mk b/packages/DocumentsUI/Android.mk
index 3197abd..568e200 100644
--- a/packages/DocumentsUI/Android.mk
+++ b/packages/DocumentsUI/Android.mk
@@ -2,6 +2,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
+LOCAL_PRIVILEGED_MODULE := true
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index e7b2ed1..fba25ab 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -1110,7 +1110,7 @@
List<String> enabled = new ArrayList<String>();
for (String id : mAdapter.getModelIds()) {
Cursor cursor = getModel().getItem(id);
- if (cursor != null) {
+ if (cursor == null) {
Log.w(TAG, "Skipping selection. Can't obtain cursor for modeId: " + id);
continue;
}
@@ -1202,7 +1202,7 @@
String id = getModelId(v);
if (id != null) {
Cursor dstCursor = mModel.getItem(id);
- if (dstCursor != null) {
+ if (dstCursor == null) {
Log.w(TAG, "Invalid destination. Can't obtain cursor for modelId: " + id);
return null;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
index 016cc9e..e6217b2 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
@@ -195,6 +195,10 @@
*/
private static final class FilesTuner extends FragmentTuner {
+ // We use this to keep track of whether a model has been previously loaded or not so we can
+ // open the drawer on empty directories on first launch
+ private boolean mModelPreviousLoaded;
+
public FilesTuner(Context context, State state) {
super(context, state);
}
@@ -230,10 +234,12 @@
@Override
void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch) {
// When launched into empty root, open drawer.
- if (model.isEmpty() && !mState.hasInitialLocationChanged() && !isSearch) {
+ if (model.isEmpty() && !mState.hasInitialLocationChanged() && !isSearch
+ && !mModelPreviousLoaded) {
// This noops on layouts without drawer, so no need to guard.
((BaseActivity) mContext).setRootsDrawerOpen(true);
}
+ mModelPreviousLoaded = true;
}
@Override
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml
index 61966b2..09fec81 100644
--- a/packages/Keyguard/res/values/strings.xml
+++ b/packages/Keyguard/res/values/strings.xml
@@ -334,6 +334,14 @@
<!-- An explanation text that the password needs to be entered since profiles have just been switched. [CHAR LIMIT=80] -->
<string name="kg_prompt_reason_switch_profiles_password">Password required when you switch profiles</string>
+ <!-- An explanation text that the credential needs to be entered because a device admin has
+ locked the device. [CHAR LIMIT=80] -->
+ <string name="kg_prompt_reason_device_admin">Device administrator locked device</string>
+
+ <!-- An explanation text that the credential needs to be entered because the user has clicked
+ the force lock button. [CHAR LIMIT=80] -->
+ <string name="kg_prompt_reason_user_request">Device was locked manually</string>
+
<!-- An explanation text that the pattern needs to be solved since it hasn't been solved in a while. [CHAR LIMIT=80]-->
<plurals name="kg_prompt_reason_time_pattern">
<item quantity="one">Device hasn\'t been unlocked for <xliff:g id="number">%d</xliff:g> hour. Confirm pattern.</item>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
index 63dec8b..189f5b7 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
@@ -117,6 +117,10 @@
return R.string.kg_prompt_reason_restart_password;
case PROMPT_REASON_TIMEOUT:
return R.string.kg_prompt_reason_timeout_password;
+ case PROMPT_REASON_DEVICE_ADMIN:
+ return R.string.kg_prompt_reason_device_admin;
+ case PROMPT_REASON_USER_REQUEST:
+ return R.string.kg_prompt_reason_user_request;
case PROMPT_REASON_NONE:
return 0;
default:
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index be2701d..e070492 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -339,6 +339,14 @@
mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_timeout_pattern,
true /* important */);
break;
+ case PROMPT_REASON_DEVICE_ADMIN:
+ mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_device_admin,
+ true /* important */);
+ break;
+ case PROMPT_REASON_USER_REQUEST:
+ mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_user_request,
+ true /* important */);
+ break;
case PROMPT_REASON_NONE:
break;
default:
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
index fe98cb8..f14290a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -108,6 +108,10 @@
return R.string.kg_prompt_reason_restart_pin;
case PROMPT_REASON_TIMEOUT:
return R.string.kg_prompt_reason_timeout_pin;
+ case PROMPT_REASON_DEVICE_ADMIN:
+ return R.string.kg_prompt_reason_device_admin;
+ case PROMPT_REASON_USER_REQUEST:
+ return R.string.kg_prompt_reason_user_request;
case PROMPT_REASON_NONE:
return 0;
default:
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index e7aebdd..c411186 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -320,6 +320,8 @@
mFileProvider, new RemotePrintDocument.RemoteAdapterDeathObserver() {
@Override
public void onDied() {
+ Log.w(LOG_TAG, "Printing app died unexpectedly");
+
// If we are finishing or we are in a state that we do not need any
// data from the printing app, then no need to finish.
if (isFinishing() || (isFinalState(mState) && !mPrintedDocument.isUpdating())) {
diff --git a/packages/Shell/res/layout/confirm_repeat.xml b/packages/Shell/res/layout/confirm_repeat.xml
index d12f467..ad90af1 100644
--- a/packages/Shell/res/layout/confirm_repeat.xml
+++ b/packages/Shell/res/layout/confirm_repeat.xml
@@ -38,5 +38,5 @@
android:id="@android:id/checkbox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:text="@string/bugreport_confirm_repeat" />
+ android:text="@string/bugreport_confirm_dont_repeat" />
</LinearLayout>
diff --git a/packages/Shell/res/values/strings.xml b/packages/Shell/res/values/strings.xml
index bee15dd..95e36fd 100644
--- a/packages/Shell/res/values/strings.xml
+++ b/packages/Shell/res/values/strings.xml
@@ -35,9 +35,9 @@
<string name="bugreport_finished_pending_screenshot_text" product="default">Tap to share your bug report without a screenshot or wait for the screenshot to finish</string>
<!-- Body of dialog informing user about contents of a bugreport. [CHAR LIMIT=NONE] -->
- <string name="bugreport_confirm">Bug reports contain data from the system\'s various log files, including personal and private information. Only share bug reports with apps and people you trust.</string>
- <!-- Checkbox that indicates this dialog should be shown again when the next bugreport is taken. [CHAR LIMIT=50] -->
- <string name="bugreport_confirm_repeat">Show this message next time</string>
+ <string name="bugreport_confirm">Bug reports contain data from the system\'s various log files, which may include data you consider sensitive (such as app-usage and location data). Only share bug reports with people and apps you trust.</string>
+ <!-- Checkbox that indicates this dialog should not be shown again when the next bugreport is taken. [CHAR LIMIT=50] -->
+ <string name="bugreport_confirm_dont_repeat">Don\'t show again</string>
<!-- Title for documents backend that offers bugreports. -->
<string name="bugreport_storage_title">Bug reports</string>
diff --git a/packages/Shell/src/com/android/shell/BugreportPrefs.java b/packages/Shell/src/com/android/shell/BugreportPrefs.java
index 3748e89..93690d4 100644
--- a/packages/Shell/src/com/android/shell/BugreportPrefs.java
+++ b/packages/Shell/src/com/android/shell/BugreportPrefs.java
@@ -22,22 +22,24 @@
/**
* Preferences related to bug reports.
*/
-public class BugreportPrefs {
- private static final String PREFS_BUGREPORT = "bugreports";
+final class BugreportPrefs {
+ static final String PREFS_BUGREPORT = "bugreports";
private static final String KEY_WARNING_STATE = "warning-state";
- public static final int STATE_UNKNOWN = 0;
- public static final int STATE_SHOW = 1;
- public static final int STATE_HIDE = 2;
+ static final int STATE_UNKNOWN = 0;
+ // Shows the warning dialog.
+ static final int STATE_SHOW = 1;
+ // Skips the warning dialog.
+ static final int STATE_HIDE = 2;
- public static int getWarningState(Context context, int def) {
+ static int getWarningState(Context context, int def) {
final SharedPreferences prefs = context.getSharedPreferences(
PREFS_BUGREPORT, Context.MODE_PRIVATE);
return prefs.getInt(KEY_WARNING_STATE, def);
}
- public static void setWarningState(Context context, int value) {
+ static void setWarningState(Context context, int value) {
final SharedPreferences prefs = context.getSharedPreferences(
PREFS_BUGREPORT, Context.MODE_PRIVATE);
prefs.edit().putInt(KEY_WARNING_STATE, value).apply();
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index f0ddcb9..502eed1 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -17,7 +17,8 @@
package com.android.shell;
import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
-import static com.android.shell.BugreportPrefs.STATE_SHOW;
+import static com.android.shell.BugreportPrefs.STATE_HIDE;
+import static com.android.shell.BugreportPrefs.STATE_UNKNOWN;
import static com.android.shell.BugreportPrefs.getWarningState;
import java.io.BufferedOutputStream;
@@ -927,7 +928,7 @@
final Intent notifIntent;
// Send through warning dialog by default
- if (getWarningState(mContext, STATE_SHOW) == STATE_SHOW) {
+ if (getWarningState(mContext, STATE_UNKNOWN) != STATE_HIDE) {
notifIntent = buildWarningIntent(mContext, sendIntent);
} else {
notifIntent = sendIntent;
diff --git a/packages/Shell/src/com/android/shell/BugreportWarningActivity.java b/packages/Shell/src/com/android/shell/BugreportWarningActivity.java
index a1d879a..da33a65 100644
--- a/packages/Shell/src/com/android/shell/BugreportWarningActivity.java
+++ b/packages/Shell/src/com/android/shell/BugreportWarningActivity.java
@@ -59,7 +59,7 @@
ap.mNegativeButtonListener = this;
mConfirmRepeat = (CheckBox) ap.mView.findViewById(android.R.id.checkbox);
- mConfirmRepeat.setChecked(getWarningState(this, STATE_UNKNOWN) == STATE_SHOW);
+ mConfirmRepeat.setChecked(getWarningState(this, STATE_UNKNOWN) != STATE_SHOW);
setupAlert();
}
@@ -68,7 +68,7 @@
public void onClick(DialogInterface dialog, int which) {
if (which == AlertDialog.BUTTON_POSITIVE) {
// Remember confirm state, and launch target
- setWarningState(this, mConfirmRepeat.isChecked() ? STATE_SHOW : STATE_HIDE);
+ setWarningState(this, mConfirmRepeat.isChecked() ? STATE_HIDE : STATE_SHOW);
startActivity(mSendIntent);
}
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index 3eb7754..537e4c5 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -17,7 +17,14 @@
package com.android.shell;
import static android.test.MoreAsserts.assertContainsRegex;
+
import static com.android.shell.ActionSendMultipleConsumerActivity.UI_NAME;
+import static com.android.shell.BugreportPrefs.PREFS_BUGREPORT;
+import static com.android.shell.BugreportPrefs.STATE_HIDE;
+import static com.android.shell.BugreportPrefs.STATE_SHOW;
+import static com.android.shell.BugreportPrefs.STATE_UNKNOWN;
+import static com.android.shell.BugreportPrefs.getWarningState;
+import static com.android.shell.BugreportPrefs.setWarningState;
import static com.android.shell.BugreportProgressService.EXTRA_BUGREPORT;
import static com.android.shell.BugreportProgressService.EXTRA_ID;
import static com.android.shell.BugreportProgressService.EXTRA_MAX;
@@ -48,12 +55,12 @@
import java.util.zip.ZipOutputStream;
import libcore.io.Streams;
+
import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo;
import android.app.Instrumentation;
import android.app.NotificationManager;
import android.content.Context;
-import android.content.ContextWrapper;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
@@ -62,7 +69,6 @@
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject;
import android.support.test.uiautomator.UiObjectNotFoundException;
-import android.support.test.uiautomator.UiSelector;
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.LargeTest;
import android.text.TextUtils;
@@ -70,7 +76,6 @@
import android.util.Log;
import com.android.shell.ActionSendMultipleConsumerActivity.CustomActionSendMultipleListener;
-import com.android.shell.BugreportProgressService;
/**
* Integration tests for {@link BugreportReceiver}.
@@ -168,7 +173,7 @@
}
mDescription = sb.toString();
- BugreportPrefs.setWarningState(mContext, BugreportPrefs.STATE_HIDE);
+ setWarningState(mContext, STATE_HIDE);
}
public void testProgress() throws Exception {
@@ -500,9 +505,29 @@
assertServiceNotRunning();
}
- public void testBugreportFinished_withWarning() throws Exception {
- // Explicitly shows the warning.
- BugreportPrefs.setWarningState(mContext, BugreportPrefs.STATE_SHOW);
+ public void testBugreportFinished_withWarningFirstTime() throws Exception {
+ bugreportFinishedWithWarningTest(null);
+ }
+
+ public void testBugreportFinished_withWarningUnknownState() throws Exception {
+ bugreportFinishedWithWarningTest(STATE_UNKNOWN);
+ }
+
+ public void testBugreportFinished_withWarningShowAgain() throws Exception {
+ bugreportFinishedWithWarningTest(STATE_SHOW);
+ }
+
+ private void bugreportFinishedWithWarningTest(Integer propertyState) throws Exception {
+ if (propertyState == null) {
+ // Clear properties
+ mContext.getSharedPreferences(PREFS_BUGREPORT, Context.MODE_PRIVATE)
+ .edit().clear().commit();
+ // Sanity check...
+ assertEquals("Did not reset properties", STATE_UNKNOWN,
+ getWarningState(mContext, STATE_UNKNOWN));
+ } else {
+ setWarningState(mContext, propertyState);
+ }
// Send notification and click on share.
sendBugreportFinished(NO_ID, mPlainTextPath, null);
@@ -510,10 +535,16 @@
// Handle the warning
mUiBot.getVisibleObject(mContext.getString(R.string.bugreport_confirm));
- // TODO: get ok and showMessageAgain from the dialog reference above
- UiObject showMessageAgain =
- mUiBot.getVisibleObject(mContext.getString(R.string.bugreport_confirm_repeat));
- mUiBot.click(showMessageAgain, "show-message-again");
+ // TODO: get ok and dontShowAgain from the dialog reference above
+ UiObject dontShowAgain =
+ mUiBot.getVisibleObject(mContext.getString(R.string.bugreport_confirm_dont_repeat));
+ final boolean firstTime = propertyState == null || propertyState == STATE_UNKNOWN;
+ if (firstTime) {
+ assertTrue("Checkbox should be checked by default", dontShowAgain.isChecked());
+ } else {
+ assertFalse("Checkbox should not be checked", dontShowAgain.isChecked());
+ mUiBot.click(dontShowAgain, "dont-show-again");
+ }
UiObject ok = mUiBot.getVisibleObject(mContext.getString(com.android.internal.R.string.ok));
mUiBot.click(ok, "ok");
@@ -523,8 +554,8 @@
assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT);
// Make sure it's hidden now.
- int newState = BugreportPrefs.getWarningState(mContext, BugreportPrefs.STATE_UNKNOWN);
- assertEquals("Didn't change state", BugreportPrefs.STATE_HIDE, newState);
+ int newState = getWarningState(mContext, STATE_UNKNOWN);
+ assertEquals("Didn't change state", STATE_HIDE, newState);
}
public void testShareBugreportAfterServiceDies() throws Exception {
@@ -876,8 +907,8 @@
}
private String getPath(String file) {
- File rootDir = new ContextWrapper(mContext).getFilesDir();
- File dir = new File(rootDir, BUGREPORTS_DIR);
+ final File rootDir = mContext.getFilesDir();
+ final File dir = new File(rootDir, BUGREPORTS_DIR);
if (!dir.exists()) {
Log.i(TAG, "Creating directory " + dir);
assertTrue("Could not create directory " + dir, dir.mkdir());
diff --git a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
index 9dd3ad2..55d7fab 100644
--- a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
+++ b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
@@ -33,7 +33,9 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
- android:gravity="center" />
+ android:gravity="center"
+ android:importantForAccessibility="yes"
+ android:focusable="true" />
<TextView
android:id="@android:id/edit"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index dc9ffa9..a4d7a18 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1595,4 +1595,7 @@
<!-- accessibility label for button to expand quick settings [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_expand">Expand quick settings.</string>
+ <!-- accessibility label for paging indicator in quick settings [CHAR LIMITi=NONE] -->
+ <string name="accessibility_quick_settings_page">Page <xliff:g name="current_page" example="1">%1$d</xliff:g> of <xliff:g name="num_pages" example="2">%2$d</xliff:g></string>
+
</resources>
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index a130cf9..1af9075 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -100,10 +100,12 @@
</PreferenceScreen>
+ <!--
<Preference
android:key="color_transform"
android:title="@string/color_and_appearance"
android:fragment="com.android.systemui.tuner.ColorAndAppearanceFragment" />
+ -->
<PreferenceScreen
android:key="volume_and_do_not_disturb"
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index f892fd6..1abd073 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1477,12 +1477,14 @@
private void sendUserPresentBroadcast() {
synchronized (this) {
if (mBootCompleted) {
- final UserHandle currentUser = new UserHandle(KeyguardUpdateMonitor.getCurrentUser());
+ int currentUserId = KeyguardUpdateMonitor.getCurrentUser();
+ final UserHandle currentUser = new UserHandle(currentUserId);
final UserManager um = (UserManager) mContext.getSystemService(
Context.USER_SERVICE);
for (int profileId : um.getProfileIdsWithDisabled(currentUser.getIdentifier())) {
mContext.sendBroadcastAsUser(USER_PRESENT_INTENT, UserHandle.of(profileId));
}
+ getLockPatternUtils().userPresent(currentUserId);
} else {
mBootSendUserPresent = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
index 5cb46ac..e050b0d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
@@ -60,6 +60,8 @@
public void setLocation(float location) {
int index = (int) location;
+ setContentDescription(getContext().getString(R.string.accessibility_quick_settings_page,
+ (index + 1), getChildCount()));
int position = index << 1 | ((location != index) ? 1 : 0);
if (DEBUG) Log.d(TAG, "setLocation " + location + " " + index + " " + position);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
index fe91f42..76aab59d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
@@ -19,6 +19,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.util.Log;
import android.view.View;
@@ -77,7 +78,7 @@
public static final int ENTER_FROM_HOME_ALPHA_DURATION = 100;
public static final int ENTER_FROM_HOME_TRANSLATION_DURATION = 333;
- public static final int ENTER_WHILE_DOCKING_DURATION = 150;
+ public static final int ENTER_WHILE_DOCKING_DURATION = 250;
private static final PathInterpolator ENTER_FROM_HOME_TRANSLATION_INTERPOLATOR =
new PathInterpolator(0, 0, 0, 1f);
@@ -135,6 +136,8 @@
R.dimen.recents_task_stack_animation_affiliate_enter_offset);
int launchedWhileDockingOffset = res.getDimensionPixelSize(
R.dimen.recents_task_stack_animation_launched_while_docking_offset);
+ boolean isLandscape = mStackView.getContext().getApplicationContext().getResources()
+ .getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
// Prepare each of the task views for their enter animation from front to back
List<TaskView> taskViews = mStackView.getTaskViews();
@@ -169,7 +172,10 @@
mTmpTransform.alpha = 0f;
mStackView.updateTaskViewToTransform(tv, mTmpTransform, AnimationProps.IMMEDIATE);
} else if (launchState.launchedViaDockGesture) {
- mTmpTransform.rect.offset(0, launchedWhileDockingOffset);
+ int offset = isLandscape
+ ? launchedWhileDockingOffset
+ : (int) (offscreenYOffset * 0.9f);
+ mTmpTransform.rect.offset(0, offset);
mTmpTransform.alpha = 0f;
mStackView.updateTaskViewToTransform(tv, mTmpTransform, AnimationProps.IMMEDIATE);
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index a6c75e8..66a413c 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -332,13 +332,18 @@
public void stopDragging(int position, SnapTarget target, long duration,
Interpolator interpolator) {
- stopDragging(position, target, duration, 0 /* startDelay*/, interpolator);
+ stopDragging(position, target, duration, 0 /* startDelay*/, 0 /* endDelay */, interpolator);
+ }
+
+ public void stopDragging(int position, SnapTarget target, long duration,
+ Interpolator interpolator, long endDelay) {
+ stopDragging(position, target, duration, 0 /* startDelay*/, endDelay, interpolator);
}
public void stopDragging(int position, SnapTarget target, long duration, long startDelay,
- Interpolator interpolator) {
+ long endDelay, Interpolator interpolator) {
mHandle.setTouching(false, true /* animate */);
- flingTo(position, target, duration, startDelay, interpolator);
+ flingTo(position, target, duration, startDelay, endDelay, interpolator);
mWindowManager.setSlippery(true);
releaseBackground();
}
@@ -471,21 +476,22 @@
if (logMetrics) {
logResizeEvent(snapTarget);
}
- ValueAnimator anim = getFlingAnimator(position, snapTarget);
+ ValueAnimator anim = getFlingAnimator(position, snapTarget, 0 /* endDelay */);
mFlingAnimationUtils.apply(anim, position, snapTarget.position, velocity);
anim.start();
}
private void flingTo(int position, SnapTarget target, long duration, long startDelay,
- Interpolator interpolator) {
- ValueAnimator anim = getFlingAnimator(position, target);
+ long endDelay, Interpolator interpolator) {
+ ValueAnimator anim = getFlingAnimator(position, target, endDelay);
anim.setDuration(duration);
anim.setStartDelay(startDelay);
anim.setInterpolator(interpolator);
anim.start();
}
- private ValueAnimator getFlingAnimator(int position, final SnapTarget snapTarget) {
+ private ValueAnimator getFlingAnimator(int position, final SnapTarget snapTarget,
+ final long endDelay) {
ValueAnimator anim = ValueAnimator.ofInt(position, snapTarget.position);
anim.addUpdateListener(new AnimatorUpdateListener() {
@Override
@@ -496,16 +502,31 @@
: snapTarget.position, snapTarget);
}
});
+ Runnable endAction = () -> {
+ commitSnapFlags(snapTarget);
+ mWindowManagerProxy.setResizing(false);
+ mDockSide = WindowManager.DOCKED_INVALID;
+ mCurrentAnimator = null;
+ mEntranceAnimationRunning = false;
+ mExitAnimationRunning = false;
+ EventBus.getDefault().send(new StoppedDragingEvent());
+ };
anim.addListener(new AnimatorListenerAdapter() {
+
+ private boolean mCancelled;
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mCancelled = true;
+ }
+
@Override
public void onAnimationEnd(Animator animation) {
- commitSnapFlags(snapTarget);
- mWindowManagerProxy.setResizing(false);
- mDockSide = WindowManager.DOCKED_INVALID;
- mCurrentAnimator = null;
- mEntranceAnimationRunning = false;
- mExitAnimationRunning = false;
- EventBus.getDefault().send(new StoppedDragingEvent());
+ if (endDelay == 0 || mCancelled) {
+ endAction.run();
+ } else {
+ postDelayed(endAction, endDelay);
+ }
}
});
mCurrentAnimator = anim;
@@ -733,8 +754,10 @@
mDockSide, mDockedTaskRect);
calculateBoundsForPosition(mExitStartPosition,
DockedDividerUtils.invertDockSide(mDockSide), mOtherTaskRect);
+ mOtherInsetRect.set(mOtherTaskRect);
+ applyExitAnimationParallax(mOtherTaskRect, position);
mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, null,
- mOtherTaskRect, null);
+ mOtherTaskRect, mOtherInsetRect);
} else if (taskPosition != TASK_POSITION_SAME) {
calculateBoundsForPosition(position, DockedDividerUtils.invertDockSide(mDockSide),
mOtherRect);
@@ -773,6 +796,16 @@
dimFraction);
}
+ private void applyExitAnimationParallax(Rect taskRect, int position) {
+ if (mDockSide == WindowManager.DOCKED_TOP) {
+ taskRect.offset(0, (int) ((position - mExitStartPosition) * 0.25f));
+ } else if (mDockSide == WindowManager.DOCKED_LEFT) {
+ taskRect.offset((int) ((position - mExitStartPosition) * 0.25f), 0);
+ } else if (mDockSide == WindowManager.DOCKED_RIGHT) {
+ taskRect.offset((int) ((mExitStartPosition - position) * 0.25f), 0);
+ }
+ }
+
private float getDimFraction(int position, SnapTarget dismissTarget) {
if (mEntranceAnimationRunning) {
return 0f;
@@ -956,14 +989,17 @@
if (mAnimateAfterRecentsDrawn) {
mAnimateAfterRecentsDrawn = false;
updateDockSide();
- stopDragging(getCurrentPosition(), mSnapAlgorithm.getMiddleTarget(), 250,
- Interpolators.TOUCH_RESPONSE);
+
+ // Delay switching resizing mode because this might cause jank in recents animation
+ // that's long than this animation.
+ stopDragging(getCurrentPosition(), mSnapAlgorithm.getMiddleTarget(),
+ 250 /* startDelay */, Interpolators.FAST_OUT_SLOW_IN, 200 /* endDelay */);
}
if (mGrowAfterRecentsDrawn) {
mGrowAfterRecentsDrawn = false;
updateDockSide();
stopDragging(getCurrentPosition(), mSnapAlgorithm.getMiddleTarget(), 250,
- Interpolators.TOUCH_RESPONSE);
+ Interpolators.FAST_OUT_SLOW_IN);
}
}
@@ -979,7 +1015,7 @@
mExitAnimationRunning = true;
mExitStartPosition = getCurrentPosition();
stopDragging(mExitStartPosition, target, 336 /* duration */, 100 /* startDelay */,
- Interpolators.TOUCH_RESPONSE);
+ 0 /* endDelay */, Interpolators.FAST_OUT_SLOW_IN);
// Vibrate after undocking
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 7fbb176..74bd096 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -30,6 +30,7 @@
import com.android.systemui.BatteryMeterView;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.qs.QSPanel;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
import com.android.systemui.statusbar.policy.UserInfoController;
@@ -150,6 +151,10 @@
});
}
+ public void setQSPanel(QSPanel qsp) {
+ mMultiUserSwitch.setQsPanel(qsp);
+ }
+
@Override
public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
index 54af684..6698d13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -127,10 +127,10 @@
mTmpInt2);
}
} else {
- Intent intent = ContactsContract.QuickContact.composeQuickContactsIntent(
- getContext(), v, ContactsContract.Profile.CONTENT_URI,
- ContactsContract.QuickContact.MODE_LARGE, null);
if (mQsPanel != null) {
+ Intent intent = ContactsContract.QuickContact.composeQuickContactsIntent(
+ getContext(), v, ContactsContract.Profile.CONTENT_URI,
+ ContactsContract.QuickContact.MODE_LARGE, null);
mQsPanel.getHost().startActivityDismissingKeyguard(intent);
}
}
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 5423f9d..4f3a6a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -893,6 +893,7 @@
qsContainer.setHost(qsh);
mQSPanel = qsContainer.getQsPanel();
mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
+ mKeyguardStatusBar.setQSPanel(mQSPanel);
mHeader = qsContainer.getHeader();
initSignalCluster(mHeader);
mHeader.setActivityStarter(PhoneStatusBar.this);
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
index ae104cd..5e5da74 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
@@ -36,7 +36,8 @@
super.onCreate(savedInstanceState);
if (getFragmentManager().findFragmentByTag(TAG_TUNER) == null) {
- boolean showDemoMode = getIntent().getAction().equals(
+ final String action = getIntent().getAction();
+ boolean showDemoMode = action != null && action.equals(
"com.android.settings.action.DEMO_MODE");
boolean showNightMode = getIntent().getBooleanExtra(
NightModeFragment.EXTRA_SHOW_NIGHT_MODE, false);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 613f890..4d7f82d 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -70,12 +70,22 @@
static final int FLAG_FEATURE_AUTOCLICK = 0x00000008;
/**
- * Flag for enabling motion event injectsion
+ * Flag for enabling motion event injection.
*
* @see #setUserAndEnabledFeatures(int, int)
*/
static final int FLAG_FEATURE_INJECT_MOTION_EVENTS = 0x00000010;
+ /**
+ * Flag for enabling the feature to control the screen magnifier. If
+ * {@link #FLAG_FEATURE_SCREEN_MAGNIFIER} is set this flag is ignored
+ * as the screen magnifier feature performs a super set of the work
+ * performed by this feature.
+ *
+ * @see #setUserAndEnabledFeatures(int, int)
+ */
+ static final int FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER = 0x00000020;
+
private final Runnable mProcessBatchedEventsRunnable = new Runnable() {
@Override
public void run() {
@@ -373,8 +383,12 @@
addFirstEventHandler(mTouchExplorer);
}
- if ((mEnabledFeatures & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0) {
- mMagnificationGestureHandler = new MagnificationGestureHandler(mContext, mAms);
+ if ((mEnabledFeatures & FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER) != 0
+ || (mEnabledFeatures & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0) {
+ final boolean detectControlGestures = (mEnabledFeatures
+ & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0;
+ mMagnificationGestureHandler = new MagnificationGestureHandler(
+ mContext, mAms, detectControlGestures);
addFirstEventHandler(mMagnificationGestureHandler);
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index ca17c43..d900b37 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1311,6 +1311,9 @@
if (userState.mIsDisplayMagnificationEnabled) {
flags |= AccessibilityInputFilter.FLAG_FEATURE_SCREEN_MAGNIFIER;
}
+ if (userHasMagnificationServicesLocked(userState)) {
+ flags |= AccessibilityInputFilter.FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER;
+ }
// Touch exploration without accessibility makes no sense.
if (userState.isHandlingAccessibilityEvents()
&& userState.mIsTouchExplorationEnabled) {
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
index 51c8ab5..818ac81 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
@@ -80,7 +80,6 @@
private static final boolean DEBUG_STATE_TRANSITIONS = false;
private static final boolean DEBUG_DETECTING = false;
private static final boolean DEBUG_PANNING = false;
- private static final boolean DEBUG_SCALING = false;
private static final int STATE_DELEGATING = 1;
private static final int STATE_DETECTING = 2;
@@ -95,6 +94,9 @@
private final MagnifiedContentInteractionStateHandler mMagnifiedContentInteractionStateHandler;
private final StateViewportDraggingHandler mStateViewportDraggingHandler;
+
+ private final boolean mDetectControlGestures;
+
private EventStreamTransformation mNext;
private int mCurrentState;
@@ -107,12 +109,14 @@
private long mDelegatingStateDownTime;
- public MagnificationGestureHandler(Context context, AccessibilityManagerService ams) {
+ public MagnificationGestureHandler(Context context, AccessibilityManagerService ams,
+ boolean detectControlGestures) {
mMagnificationController = ams.getMagnificationController();
mDetectingStateHandler = new DetectingStateHandler(context);
mStateViewportDraggingHandler = new StateViewportDraggingHandler();
mMagnifiedContentInteractionStateHandler =
new MagnifiedContentInteractionStateHandler(context);
+ mDetectControlGestures = detectControlGestures;
transitionToState(STATE_DETECTING);
}
@@ -125,6 +129,12 @@
}
return;
}
+ if (!mDetectControlGestures) {
+ if (mNext != null) {
+ dispatchTransformedEvent(event, rawEvent, policyFlags);
+ }
+ return;
+ }
mMagnifiedContentInteractionStateHandler.onMotionEvent(event, rawEvent, policyFlags);
switch (mCurrentState) {
case STATE_DELEGATING: {
@@ -140,7 +150,7 @@
}
break;
case STATE_MAGNIFIED_INTERACTION: {
- // mMagnifiedContentInteractonStateHandler handles events only
+ // mMagnifiedContentInteractionStateHandler handles events only
// if this is the current state since it uses ScaleGestureDetecotr
// and a GestureDetector which need well formed event stream.
}
@@ -208,31 +218,6 @@
break;
}
if (mNext != null) {
- // If the event is within the magnified portion of the screen we have
- // to change its location to be where the user thinks he is poking the
- // UI which may have been magnified and panned.
- final float eventX = event.getX();
- final float eventY = event.getY();
- if (mMagnificationController.isMagnifying()
- && mMagnificationController.magnifiedRegionContains(eventX, eventY)) {
- final float scale = mMagnificationController.getScale();
- final float scaledOffsetX = mMagnificationController.getOffsetX();
- final float scaledOffsetY = mMagnificationController.getOffsetY();
- final int pointerCount = event.getPointerCount();
- PointerCoords[] coords = getTempPointerCoordsWithMinSize(pointerCount);
- PointerProperties[] properties = getTempPointerPropertiesWithMinSize(
- pointerCount);
- for (int i = 0; i < pointerCount; i++) {
- event.getPointerCoords(i, coords[i]);
- coords[i].x = (coords[i].x - scaledOffsetX) / scale;
- coords[i].y = (coords[i].y - scaledOffsetY) / scale;
- event.getPointerProperties(i, properties[i]);
- }
- event = MotionEvent.obtain(event.getDownTime(),
- event.getEventTime(), event.getAction(), pointerCount, properties,
- coords, 0, 0, 1.0f, 1.0f, event.getDeviceId(), 0, event.getSource(),
- event.getFlags());
- }
// We cache some events to see if the user wants to trigger magnification.
// If no magnification is triggered we inject these events with adjusted
// time and down time to prevent subsequent transformations being confused
@@ -240,10 +225,40 @@
// injected we need to also update the down time of all subsequent non cached
// events. All delegated events cached and non-cached are delivered here.
event.setDownTime(mDelegatingStateDownTime);
- mNext.onMotionEvent(event, rawEvent, policyFlags);
+ dispatchTransformedEvent(event, rawEvent, policyFlags);
}
}
+ private void dispatchTransformedEvent(MotionEvent event, MotionEvent rawEvent,
+ int policyFlags) {
+ // If the event is within the magnified portion of the screen we have
+ // to change its location to be where the user thinks he is poking the
+ // UI which may have been magnified and panned.
+ final float eventX = event.getX();
+ final float eventY = event.getY();
+ if (mMagnificationController.isMagnifying()
+ && mMagnificationController.magnifiedRegionContains(eventX, eventY)) {
+ final float scale = mMagnificationController.getScale();
+ final float scaledOffsetX = mMagnificationController.getOffsetX();
+ final float scaledOffsetY = mMagnificationController.getOffsetY();
+ final int pointerCount = event.getPointerCount();
+ PointerCoords[] coords = getTempPointerCoordsWithMinSize(pointerCount);
+ PointerProperties[] properties = getTempPointerPropertiesWithMinSize(
+ pointerCount);
+ for (int i = 0; i < pointerCount; i++) {
+ event.getPointerCoords(i, coords[i]);
+ coords[i].x = (coords[i].x - scaledOffsetX) / scale;
+ coords[i].y = (coords[i].y - scaledOffsetY) / scale;
+ event.getPointerProperties(i, properties[i]);
+ }
+ event = MotionEvent.obtain(event.getDownTime(),
+ event.getEventTime(), event.getAction(), pointerCount, properties,
+ coords, 0, 0, 1.0f, 1.0f, event.getDeviceId(), 0, event.getSource(),
+ event.getFlags());
+ }
+ mNext.onMotionEvent(event, rawEvent, policyFlags);
+ }
+
private PointerCoords[] getTempPointerCoordsWithMinSize(int size) {
final int oldSize = (mTempPointerCoords != null) ? mTempPointerCoords.length : 0;
if (oldSize < size) {
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 6ca3af8..0428ecf 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -613,23 +613,22 @@
| FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
}
}
+ for (int j = 0; j < widgetCount; j++) {
+ Widget widget = provider.widgets.get(j);
+ if (targetWidget != null && targetWidget != widget) continue;
+ PendingIntent intent = null;
+ if (onClickIntent != null) {
+ intent = PendingIntent.getActivity(mContext, widget.appWidgetId,
+ onClickIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+ RemoteViews views = createMaskedWidgetRemoteViews(iconBitmap, showBadge, intent);
+ if (widget.replaceWithMaskedViewsLocked(views)) {
+ scheduleNotifyUpdateAppWidgetLocked(widget, widget.getEffectiveViewsLocked());
+ }
+ }
} finally {
Binder.restoreCallingIdentity(identity);
}
-
- for (int j = 0; j < widgetCount; j++) {
- Widget widget = provider.widgets.get(j);
- if (targetWidget != null && targetWidget != widget) continue;
- PendingIntent intent = null;
- if (onClickIntent != null) {
- intent = PendingIntent.getActivity(mContext, widget.appWidgetId,
- onClickIntent, PendingIntent.FLAG_UPDATE_CURRENT);
- }
- RemoteViews views = createMaskedWidgetRemoteViews(iconBitmap, showBadge, intent);
- if (widget.replaceWithMaskedViewsLocked(views)) {
- scheduleNotifyUpdateAppWidgetLocked(widget, widget.getEffectiveViewsLocked());
- }
- }
}
private void unmaskWidgetsViewsLocked(Provider provider) {
@@ -1062,8 +1061,6 @@
widget.provider = provider;
widget.options = (options != null) ? cloneIfLocalBinder(options) : new Bundle();
- onWidgetProviderAddedOrChangedLocked(widget);
-
// We need to provide a default value for the widget category if it is not specified
if (!widget.options.containsKey(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY)) {
widget.options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
@@ -1072,6 +1069,8 @@
provider.widgets.add(widget);
+ onWidgetProviderAddedOrChangedLocked(widget);
+
final int widgetCount = provider.widgets.size();
if (widgetCount == 1) {
// Tell the provider that it's ready.
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 4ac75ca..f2b4e52 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -229,7 +229,6 @@
filter.addAction(Intent.ACTION_USER_ADDED);
filter.addAction(Intent.ACTION_USER_STARTING);
filter.addAction(Intent.ACTION_USER_REMOVED);
- filter.addAction(Intent.ACTION_USER_PRESENT);
mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
mStorage = new LockSettingsStorage(context, new LockSettingsStorage.Callback() {
@@ -369,8 +368,6 @@
} else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
mStorage.prefetchUser(userHandle);
- } else if (Intent.ACTION_USER_PRESENT.equals(intent.getAction())) {
- mStrongAuth.reportUnlock(getSendingUserId());
} else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
if (userHandle > 0) {
@@ -1347,6 +1344,12 @@
mStrongAuth.requireStrongAuth(strongAuthReason, userId);
}
+ @Override
+ public void userPresent(int userId) {
+ checkWritePermission(userId);
+ mStrongAuth.reportUnlock(userId);
+ }
+
private static final String[] VALID_SETTINGS = new String[] {
LockPatternUtils.LOCKOUT_PERMANENT_KEY,
LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE,
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index bf4df94..fffd850 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -174,6 +174,16 @@
public static final int StrictCleartext = 617;
}
+ /**
+ * String indicating a softap command.
+ */
+ static final String SOFT_AP_COMMAND = "softap";
+
+ /**
+ * String passed back to netd connector indicating softap command success.
+ */
+ static final String SOFT_AP_COMMAND_SUCCESS = "Ok";
+
static final int DAEMON_MSG_MOBILE_CONN_REAL_TIME_INFO = 1;
/**
@@ -1426,20 +1436,48 @@
}
}
+ /**
+ * Private method used to call execute for a command given the provided arguments.
+ *
+ * This function checks the returned NativeDaemonEvent for the provided expected response code
+ * and message. If either of these is not correct, an error is logged.
+ *
+ * @param String command The command to execute.
+ * @param Object[] args If needed, arguments for the command to execute.
+ * @param int expectedResponseCode The code expected to be returned in the corresponding event.
+ * @param String expectedResponseMessage The message expected in the returned event.
+ * @param String logMsg The message to log as an error (TAG will be applied).
+ */
+ private void executeOrLogWithMessage(String command, Object[] args,
+ int expectedResponseCode, String expectedResponseMessage, String logMsg)
+ throws NativeDaemonConnectorException {
+ NativeDaemonEvent event = mConnector.execute(command, args);
+ if (event.getCode() != expectedResponseCode
+ || !event.getMessage().equals(expectedResponseMessage)) {
+ Log.e(TAG, logMsg + ": event = " + event);
+ }
+ }
+
@Override
- public void startAccessPoint(
- WifiConfiguration wifiConfig, String wlanIface) {
+ public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ Object[] args;
+ String logMsg = "startAccessPoint Error setting up softap";
try {
if (wifiConfig == null) {
- mConnector.execute("softap", "set", wlanIface);
+ args = new Object[] {"set", wlanIface};
} else {
- mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,
- "broadcast", Integer.toString(wifiConfig.apChannel),
- getSecurityType(wifiConfig),
- new SensitiveArg(wifiConfig.preSharedKey));
+ args = new Object[] {"set", wlanIface, wifiConfig.SSID,
+ "broadcast", Integer.toString(wifiConfig.apChannel),
+ getSecurityType(wifiConfig), new SensitiveArg(wifiConfig.preSharedKey)};
}
- mConnector.execute("softap", "startap");
+ executeOrLogWithMessage(SOFT_AP_COMMAND, args, NetdResponseCode.SoftapStatusResult,
+ SOFT_AP_COMMAND_SUCCESS, logMsg);
+
+ logMsg = "startAccessPoint Error starting softap";
+ args = new Object[] {"startap"};
+ executeOrLogWithMessage(SOFT_AP_COMMAND, args, NetdResponseCode.SoftapStatusResult,
+ SOFT_AP_COMMAND_SUCCESS, logMsg);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
@@ -1460,8 +1498,12 @@
@Override
public void wifiFirmwareReload(String wlanIface, String mode) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ Object[] args = {"fwreload", wlanIface, mode};
+ String logMsg = "wifiFirmwareReload Error reloading "
+ + wlanIface + " fw in " + mode + " mode";
try {
- mConnector.execute("softap", "fwreload", wlanIface, mode);
+ executeOrLogWithMessage(SOFT_AP_COMMAND, args, NetdResponseCode.SoftapStatusResult,
+ SOFT_AP_COMMAND_SUCCESS, logMsg);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
@@ -1470,8 +1512,12 @@
@Override
public void stopAccessPoint(String wlanIface) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ Object[] args = {"stopap"};
+ String logMsg = "stopAccessPoint Error stopping softap";
+
try {
- mConnector.execute("softap", "stopap");
+ executeOrLogWithMessage(SOFT_AP_COMMAND, args, NetdResponseCode.SoftapStatusResult,
+ SOFT_AP_COMMAND_SUCCESS, logMsg);
wifiFirmwareReload(wlanIface, "STA");
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
@@ -1481,14 +1527,21 @@
@Override
public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ Object[] args;
+ String logMsg = "startAccessPoint Error setting up softap";
try {
if (wifiConfig == null) {
- mConnector.execute("softap", "set", wlanIface);
+ args = new Object[] {"set", wlanIface};
} else {
- mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,
- "broadcast", "6", getSecurityType(wifiConfig),
- new SensitiveArg(wifiConfig.preSharedKey));
+ // TODO: understand why this is set to "6" instead of
+ // Integer.toString(wifiConfig.apChannel) as in startAccessPoint
+ // TODO: should startAccessPoint call this instead of repeating code?
+ args = new Object[] {"set", wlanIface, wifiConfig.SSID,
+ "broadcast", "6",
+ getSecurityType(wifiConfig), new SensitiveArg(wifiConfig.preSharedKey)};
}
+ executeOrLogWithMessage(SOFT_AP_COMMAND, args, NetdResponseCode.SoftapStatusResult,
+ SOFT_AP_COMMAND_SUCCESS, logMsg);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c01b4f5..4c75f50 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -9425,7 +9425,8 @@
if (prev != null && prev.isRecentsActivity()) {
task.setTaskToReturnTo(ActivityRecord.RECENTS_ACTIVITY_TYPE);
}
- mStackSupervisor.findTaskToMoveToFrontLocked(task, flags, options, "moveTaskToFront");
+ mStackSupervisor.findTaskToMoveToFrontLocked(task, flags, options, "moveTaskToFront",
+ false /* forceNonResizable */);
} finally {
Binder.restoreCallingIdentity(origId);
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 53c6024..598d9ff 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1759,8 +1759,8 @@
}
}
- void findTaskToMoveToFrontLocked(
- TaskRecord task, int flags, ActivityOptions options, String reason) {
+ void findTaskToMoveToFrontLocked(TaskRecord task, int flags, ActivityOptions options,
+ String reason, boolean forceNonResizeable) {
if ((flags & ActivityManager.MOVE_TASK_NO_USER_ACTION) == 0) {
mUserLeaving = true;
}
@@ -1811,7 +1811,8 @@
if (DEBUG_STACK) Slog.d(TAG_STACK,
"findTaskToMoveToFront: moved to front of stack=" + task.stack);
- handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, task.stack.mStackId);
+ handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, task.stack.mStackId,
+ forceNonResizeable);
}
boolean canUseActivityOptionsLaunchBounds(ActivityOptions options, int launchStackId) {
@@ -3360,19 +3361,25 @@
}
}
+ void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredStackId, int actualStackId) {
+ handleNonResizableTaskIfNeeded(task, preferredStackId, actualStackId,
+ false /* forceNonResizable */);
+ }
+
void handleNonResizableTaskIfNeeded(
- TaskRecord task, int preferredStackId, int actualStackId) {
+ TaskRecord task, int preferredStackId, int actualStackId, boolean forceNonResizable) {
if ((!isStackDockedInEffect(actualStackId) && preferredStackId != DOCKED_STACK_ID)
|| task.isHomeTask()) {
return;
}
- if (!task.canGoInDockedStack()) {
+ if (!task.canGoInDockedStack() || forceNonResizable) {
// Display a warning toast that we tried to put a non-dockable task in the docked stack.
mService.mHandler.sendEmptyMessage(NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG);
- // Dismiss docked stack.
- mService.moveTasksToFullscreenStack(DOCKED_STACK_ID, false);
+ // Dismiss docked stack. If task appeared to be in docked stack but is not resizable -
+ // we need to move it to top of fullscreen stack, otherwise it will be covered.
+ mService.moveTasksToFullscreenStack(DOCKED_STACK_ID, actualStackId == DOCKED_STACK_ID);
} else if (task.mResizeMode == RESIZE_MODE_FORCE_RESIZEABLE) {
String packageName = task.getTopActivity() != null
? task.getTopActivity().appInfo.packageName : null;
@@ -3443,8 +3450,12 @@
}
if (andResume) {
- findTaskToMoveToFrontLocked(task, 0, null, reason);
+ findTaskToMoveToFrontLocked(task, 0, null, reason,
+ lockTaskModeState != LOCK_TASK_MODE_NONE);
resumeFocusedStackTopActivityLocked();
+ } else if (lockTaskModeState != LOCK_TASK_MODE_NONE) {
+ handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, task.stack.mStackId,
+ true /* forceNonResizable */);
}
}
diff --git a/services/core/java/com/android/server/job/JobPackageTracker.java b/services/core/java/com/android/server/job/JobPackageTracker.java
new file mode 100644
index 0000000..e5a2095
--- /dev/null
+++ b/services/core/java/com/android/server/job/JobPackageTracker.java
@@ -0,0 +1,361 @@
+/*
+ * 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.job;
+
+import android.app.job.JobInfo;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.text.format.DateFormat;
+import android.util.ArrayMap;
+import android.util.SparseArray;
+import android.util.TimeUtils;
+import com.android.server.job.controllers.JobStatus;
+
+import java.io.PrintWriter;
+
+public final class JobPackageTracker {
+ // We batch every 30 minutes.
+ static final long BATCHING_TIME = 30*60*1000;
+ // Number of historical data sets we keep.
+ static final int NUM_HISTORY = 5;
+
+ DataSet mCurDataSet = new DataSet();
+ DataSet[] mLastDataSets = new DataSet[NUM_HISTORY];
+
+ final static class PackageEntry {
+ long pastActiveTime;
+ long activeStartTime;
+ int activeCount;
+ boolean hadActive;
+ long pastActiveTopTime;
+ long activeTopStartTime;
+ int activeTopCount;
+ boolean hadActiveTop;
+ long pastPendingTime;
+ long pendingStartTime;
+ int pendingCount;
+ boolean hadPending;
+
+ public long getActiveTime(long now) {
+ long time = pastActiveTime;
+ if (activeCount > 0) {
+ time += now - activeStartTime;
+ }
+ return time;
+ }
+
+ public long getActiveTopTime(long now) {
+ long time = pastActiveTopTime;
+ if (activeTopCount > 0) {
+ time += now - activeTopStartTime;
+ }
+ return time;
+ }
+
+ public long getPendingTime(long now) {
+ long time = pastPendingTime;
+ if (pendingCount > 0) {
+ time += now - pendingStartTime;
+ }
+ return time;
+ }
+ }
+
+ final static class DataSet {
+ final SparseArray<ArrayMap<String, PackageEntry>> mEntries = new SparseArray<>();
+ final long mStartUptimeTime;
+ final long mStartElapsedTime;
+ final long mStartClockTime;
+ long mSummedTime;
+
+ public DataSet(DataSet otherTimes) {
+ mStartUptimeTime = otherTimes.mStartUptimeTime;
+ mStartElapsedTime = otherTimes.mStartElapsedTime;
+ mStartClockTime = otherTimes.mStartClockTime;
+ }
+
+ public DataSet() {
+ mStartUptimeTime = SystemClock.uptimeMillis();
+ mStartElapsedTime = SystemClock.elapsedRealtime();
+ mStartClockTime = System.currentTimeMillis();
+ }
+
+ private PackageEntry getOrCreateEntry(int uid, String pkg) {
+ ArrayMap<String, PackageEntry> uidMap = mEntries.get(uid);
+ if (uidMap == null) {
+ uidMap = new ArrayMap<>();
+ mEntries.put(uid, uidMap);
+ }
+ PackageEntry entry = uidMap.get(pkg);
+ if (entry == null) {
+ entry = new PackageEntry();
+ uidMap.put(pkg, entry);
+ }
+ return entry;
+ }
+
+ public PackageEntry getEntry(int uid, String pkg) {
+ ArrayMap<String, PackageEntry> uidMap = mEntries.get(uid);
+ if (uidMap == null) {
+ return null;
+ }
+ return uidMap.get(pkg);
+ }
+
+ long getTotalTime(long now) {
+ if (mSummedTime > 0) {
+ return mSummedTime;
+ }
+ return now - mStartUptimeTime;
+ }
+
+ void incPending(int uid, String pkg, long now) {
+ PackageEntry pe = getOrCreateEntry(uid, pkg);
+ if (pe.pendingCount == 0) {
+ pe.pendingStartTime = now;
+ }
+ pe.pendingCount++;
+ }
+
+ void decPending(int uid, String pkg, long now) {
+ PackageEntry pe = getOrCreateEntry(uid, pkg);
+ if (pe.pendingCount == 1) {
+ pe.pastPendingTime += now - pe.pendingStartTime;
+ }
+ pe.pendingCount--;
+ }
+
+ void incActive(int uid, String pkg, long now) {
+ PackageEntry pe = getOrCreateEntry(uid, pkg);
+ if (pe.activeCount == 0) {
+ pe.activeStartTime = now;
+ }
+ pe.activeCount++;
+ }
+
+ void decActive(int uid, String pkg, long now) {
+ PackageEntry pe = getOrCreateEntry(uid, pkg);
+ if (pe.activeCount == 1) {
+ pe.pastActiveTime += now - pe.activeStartTime;
+ }
+ pe.activeCount--;
+ }
+
+ void incActiveTop(int uid, String pkg, long now) {
+ PackageEntry pe = getOrCreateEntry(uid, pkg);
+ if (pe.activeTopCount == 0) {
+ pe.activeTopStartTime = now;
+ }
+ pe.activeTopCount++;
+ }
+
+ void decActiveTop(int uid, String pkg, long now) {
+ PackageEntry pe = getOrCreateEntry(uid, pkg);
+ if (pe.activeTopCount == 1) {
+ pe.pastActiveTopTime += now - pe.activeTopStartTime;
+ }
+ pe.activeTopCount--;
+ }
+
+ void finish(DataSet next, long now) {
+ for (int i = mEntries.size() - 1; i >= 0; i--) {
+ ArrayMap<String, PackageEntry> uidMap = mEntries.valueAt(i);
+ for (int j = uidMap.size() - 1; j >= 0; j--) {
+ PackageEntry pe = uidMap.valueAt(j);
+ if (pe.activeCount > 0 || pe.activeTopCount > 0 || pe.pendingCount > 0) {
+ // Propagate existing activity in to next data set.
+ PackageEntry nextPe = next.getOrCreateEntry(mEntries.keyAt(i), uidMap.keyAt(j));
+ nextPe.activeStartTime = now;
+ nextPe.activeCount = pe.activeCount;
+ nextPe.activeTopStartTime = now;
+ nextPe.activeTopCount = pe.activeTopCount;
+ nextPe.pendingStartTime = now;
+ nextPe.pendingCount = pe.pendingCount;
+ // Finish it off.
+ if (pe.activeCount > 0) {
+ pe.pastActiveTime += now - pe.activeStartTime;
+ pe.activeCount = 0;
+ }
+ if (pe.activeTopCount > 0) {
+ pe.pastActiveTopTime += now - pe.activeTopStartTime;
+ pe.activeTopCount = 0;
+ }
+ if (pe.pendingCount > 0) {
+ pe.pastPendingTime += now - pe.pendingStartTime;
+ pe.pendingCount = 0;
+ }
+ }
+ }
+ }
+ }
+
+ void addTo(DataSet out, long now) {
+ out.mSummedTime += getTotalTime(now);
+ for (int i = mEntries.size() - 1; i >= 0; i--) {
+ ArrayMap<String, PackageEntry> uidMap = mEntries.valueAt(i);
+ for (int j = uidMap.size() - 1; j >= 0; j--) {
+ PackageEntry pe = uidMap.valueAt(j);
+ PackageEntry outPe = out.getOrCreateEntry(mEntries.keyAt(i), uidMap.keyAt(j));
+ outPe.pastActiveTime += pe.pastActiveTime;
+ outPe.pastActiveTopTime += pe.pastActiveTopTime;
+ outPe.pastPendingTime += pe.pastPendingTime;
+ if (pe.activeCount > 0) {
+ outPe.pastActiveTime += now - pe.activeStartTime;
+ outPe.hadActive = true;
+ }
+ if (pe.activeTopCount > 0) {
+ outPe.pastActiveTopTime += now - pe.activeTopStartTime;
+ outPe.hadActiveTop = true;
+ }
+ if (pe.pendingCount > 0) {
+ outPe.pastPendingTime += now - pe.pendingStartTime;
+ outPe.hadPending = true;
+ }
+ }
+ }
+ }
+
+ void printDuration(PrintWriter pw, long period, long duration, String suffix) {
+ float fraction = duration / (float) period;
+ int percent = (int) ((fraction * 100) + .5f);
+ if (percent > 0) {
+ pw.print(" ");
+ pw.print(percent);
+ pw.print("% ");
+ pw.print(suffix);
+ }
+ }
+
+ void dump(PrintWriter pw, String header, String prefix, long now, long nowEllapsed) {
+ final long period = getTotalTime(now);
+ pw.print(prefix); pw.print(header); pw.print(" at ");
+ pw.print(DateFormat.format("yyyy-MM-dd-HH-mm-ss", mStartClockTime).toString());
+ pw.print(" (");
+ TimeUtils.formatDuration(mStartElapsedTime, nowEllapsed, pw);
+ pw.print(") over ");
+ TimeUtils.formatDuration(period, pw);
+ pw.println(":");
+ final int NE = mEntries.size();
+ for (int i = 0; i < NE; i++) {
+ ArrayMap<String, PackageEntry> uidMap = mEntries.valueAt(i);
+ final int NP = uidMap.size();
+ for (int j = 0; j < NP; j++) {
+ PackageEntry pe = uidMap.valueAt(j);
+ pw.print(prefix); pw.print(" ");
+ UserHandle.formatUid(pw, mEntries.keyAt(i));
+ pw.print(" / "); pw.print(uidMap.keyAt(j));
+ pw.print(":");
+ printDuration(pw, period, pe.getPendingTime(now), "pending");
+ printDuration(pw, period, pe.getActiveTime(now), "active");
+ printDuration(pw, period, pe.getActiveTopTime(now), "active-top");
+ if (pe.pendingCount > 0 || pe.hadPending) {
+ pw.print(" (pending)");
+ }
+ if (pe.activeCount > 0 || pe.hadActive) {
+ pw.print(" (active)");
+ }
+ if (pe.activeTopCount > 0 || pe.hadActiveTop) {
+ pw.print(" (active-top)");
+ }
+ pw.println();
+ }
+ }
+ }
+ }
+
+ void rebatchIfNeeded(long now) {
+ long totalTime = mCurDataSet.getTotalTime(now);
+ if (totalTime > BATCHING_TIME) {
+ DataSet last = mCurDataSet;
+ last.mSummedTime = totalTime;
+ mCurDataSet = new DataSet();
+ last.finish(mCurDataSet, now);
+ System.arraycopy(mLastDataSets, 0, mLastDataSets, 1, mLastDataSets.length-1);
+ mLastDataSets[0] = last;
+ }
+ }
+
+ public void notePending(JobStatus job) {
+ final long now = SystemClock.uptimeMillis();
+ rebatchIfNeeded(now);
+ mCurDataSet.incPending(job.getSourceUid(), job.getSourcePackageName(), now);
+ }
+
+ public void noteNonpending(JobStatus job) {
+ final long now = SystemClock.uptimeMillis();
+ mCurDataSet.decPending(job.getSourceUid(), job.getSourcePackageName(), now);
+ rebatchIfNeeded(now);
+ }
+
+ public void noteActive(JobStatus job) {
+ final long now = SystemClock.uptimeMillis();
+ rebatchIfNeeded(now);
+ if (job.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP) {
+ mCurDataSet.incActiveTop(job.getSourceUid(), job.getSourcePackageName(), now);
+ } else {
+ mCurDataSet.incActive(job.getSourceUid(), job.getSourcePackageName(), now);
+ }
+ }
+
+ public void noteInactive(JobStatus job) {
+ final long now = SystemClock.uptimeMillis();
+ if (job.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP) {
+ mCurDataSet.decActiveTop(job.getSourceUid(), job.getSourcePackageName(), now);
+ } else {
+ mCurDataSet.decActive(job.getSourceUid(), job.getSourcePackageName(), now);
+ }
+ rebatchIfNeeded(now);
+ }
+
+ public float getLoadFactor(JobStatus job) {
+ final int uid = job.getSourceUid();
+ final String pkg = job.getSourcePackageName();
+ PackageEntry cur = mCurDataSet.getEntry(uid, pkg);
+ PackageEntry last = mLastDataSets[0] != null ? mLastDataSets[0].getEntry(uid, pkg) : null;
+ if (cur == null && last == null) {
+ return 0;
+ }
+ final long now = SystemClock.uptimeMillis();
+ long time = cur.getActiveTime(now) + cur.getPendingTime(now);
+ long period = mCurDataSet.getTotalTime(now);
+ if (last != null) {
+ time += last.getActiveTime(now) + last.getPendingTime(now);
+ period += mLastDataSets[0].getTotalTime(now);
+ }
+ return time / (float)period;
+ }
+
+ public void dump(PrintWriter pw, String prefix) {
+ final long now = SystemClock.uptimeMillis();
+ final long nowEllapsed = SystemClock.elapsedRealtime();
+ final DataSet total;
+ if (mLastDataSets[0] != null) {
+ total = new DataSet(mLastDataSets[0]);
+ mLastDataSets[0].addTo(total, now);
+ } else {
+ total = new DataSet(mCurDataSet);
+ }
+ mCurDataSet.addTo(total, now);
+ for (int i = 1; i < mLastDataSets.length; i++) {
+ if (mLastDataSets[i] != null) {
+ mLastDataSets[i].dump(pw, "Historical stats", prefix, now, nowEllapsed);
+ pw.println();
+ }
+ }
+ total.dump(pw, "Current stats", prefix, now, nowEllapsed);
+ }
+}
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index b235002..7df8ffd 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -93,16 +93,24 @@
public static final boolean DEBUG = false;
/** The maximum number of concurrent jobs we run at one time. */
- private static final int MAX_JOB_CONTEXTS_COUNT = 8;
+ private static final int MAX_JOB_CONTEXTS_COUNT = 12;
+ /** The number of MAX_JOB_CONTEXTS_COUNT we reserve for the foreground app. */
+ private static final int FG_JOB_CONTEXTS_COUNT = 4;
/** Enforce a per-app limit on scheduled jobs? */
private static final boolean ENFORCE_MAX_JOBS = true;
/** The maximum number of jobs that we allow an unprivileged app to schedule */
private static final int MAX_JOBS_PER_APP = 100;
+ /** This is the job execution factor that is considered to be heavy use of the system. */
+ private static final float HEAVY_USE_FACTOR = .9f;
+ /** This is the job execution factor that is considered to be moderate use of the system. */
+ private static final float MODERATE_USE_FACTOR = .5f;
/** Global local for all job scheduler state. */
final Object mLock = new Object();
/** Master list of jobs. */
final JobStore mJobs;
+ /** Tracking amount of time each package runs for. */
+ final JobPackageTracker mJobPackageTracker = new JobPackageTracker();
static final int MSG_JOB_EXPIRED = 0;
static final int MSG_CHECK_JOB = 1;
@@ -173,7 +181,7 @@
* Current limit on the number of concurrent JobServiceContext entries we want to
* keep actively running a job.
*/
- int mMaxActiveJobs = MAX_JOB_CONTEXTS_COUNT - 2;
+ int mMaxActiveJobs = MAX_JOB_CONTEXTS_COUNT - FG_JOB_CONTEXTS_COUNT;
/**
* Which uids are currently in the foreground.
@@ -249,6 +257,10 @@
return mLock;
}
+ public JobStore getJobStore() {
+ return mJobs;
+ }
+
@Override
public void onStartUser(int userHandle) {
mStartedUsers = ArrayUtils.appendInt(mStartedUsers, userHandle);
@@ -386,7 +398,9 @@
stopTrackingJob(cancelled, incomingJob, true /* writeBack */);
synchronized (mLock) {
// Remove from pending queue.
- mPendingJobs.remove(cancelled);
+ if (mPendingJobs.remove(cancelled)) {
+ mJobPackageTracker.noteNonpending(cancelled);
+ }
// Cancel if running.
stopJobOnServiceContextLocked(cancelled, JobParameters.REASON_CANCELED);
reportActive();
@@ -518,7 +532,7 @@
// Create the "runners".
for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
mActiveServices.add(
- new JobServiceContext(this, mBatteryStats,
+ new JobServiceContext(this, mBatteryStats, mJobPackageTracker,
getContext().getMainLooper()));
}
// Attach jobs to their controllers.
@@ -604,6 +618,20 @@
return false;
}
+ void noteJobsPending(List<JobStatus> jobs) {
+ for (int i = jobs.size() - 1; i >= 0; i--) {
+ JobStatus job = jobs.get(i);
+ mJobPackageTracker.notePending(job);
+ }
+ }
+
+ void noteJobsNonpending(List<JobStatus> jobs) {
+ for (int i = jobs.size() - 1; i >= 0; i--) {
+ JobStatus job = jobs.get(i);
+ mJobPackageTracker.noteNonpending(job);
+ }
+ }
+
/**
* Reschedules the given job based on the job's backoff policy. It doesn't make sense to
* specify an override deadline on a failed job (the failed job will run even though it's not
@@ -759,6 +787,7 @@
// state is such that all ready jobs should be run immediately.
if (runNow != null && !mPendingJobs.contains(runNow)
&& mJobs.containsJob(runNow)) {
+ mJobPackageTracker.notePending(runNow);
mPendingJobs.add(runNow);
}
queueReadyJobsForExecutionLockedH();
@@ -797,6 +826,7 @@
if (DEBUG) {
Slog.d(TAG, "queuing all ready jobs for execution:");
}
+ noteJobsNonpending(mPendingJobs);
mPendingJobs.clear();
mJobs.forEachJob(mReadyQueueFunctor);
mReadyQueueFunctor.postProcess();
@@ -832,6 +862,7 @@
public void postProcess() {
if (newReadyJobs != null) {
+ noteJobsPending(newReadyJobs);
mPendingJobs.addAll(newReadyJobs);
}
newReadyJobs = null;
@@ -910,6 +941,7 @@
if (DEBUG) {
Slog.d(TAG, "maybeQueueReadyJobsForExecutionLockedH: Running jobs.");
}
+ noteJobsPending(runnableJobs);
mPendingJobs.addAll(runnableJobs);
} else {
if (DEBUG) {
@@ -935,6 +967,7 @@
private void maybeQueueReadyJobsForExecutionLockedH() {
if (DEBUG) Slog.d(TAG, "Maybe queuing ready jobs...");
+ noteJobsNonpending(mPendingJobs);
mPendingJobs.clear();
mJobs.forEachJob(mMaybeQueueFunctor);
mMaybeQueueFunctor.postProcess();
@@ -998,16 +1031,28 @@
}
}
+ private int adjustJobPriority(int curPriority, JobStatus job) {
+ if (curPriority < JobInfo.PRIORITY_TOP_APP) {
+ float factor = mJobPackageTracker.getLoadFactor(job);
+ if (factor >= HEAVY_USE_FACTOR) {
+ curPriority += JobInfo.PRIORITY_ADJ_ALWAYS_RUNNING;
+ } else if (factor >= MODERATE_USE_FACTOR) {
+ curPriority += JobInfo.PRIORITY_ADJ_OFTEN_RUNNING;
+ }
+ }
+ return curPriority;
+ }
+
private int evaluateJobPriorityLocked(JobStatus job) {
int priority = job.getPriority();
if (priority >= JobInfo.PRIORITY_FOREGROUND_APP) {
- return priority;
+ return adjustJobPriority(priority, job);
}
int override = mUidPriorityOverride.get(job.getSourceUid(), 0);
if (override != 0) {
- return override;
+ return adjustJobPriority(override, job);
}
- return priority;
+ return adjustJobPriority(priority, job);
}
/**
@@ -1029,16 +1074,16 @@
}
switch (memLevel) {
case ProcessStats.ADJ_MEM_FACTOR_MODERATE:
- mMaxActiveJobs = ((MAX_JOB_CONTEXTS_COUNT - 2) * 2) / 3;
+ mMaxActiveJobs = ((MAX_JOB_CONTEXTS_COUNT - FG_JOB_CONTEXTS_COUNT) * 2) / 3;
break;
case ProcessStats.ADJ_MEM_FACTOR_LOW:
- mMaxActiveJobs = (MAX_JOB_CONTEXTS_COUNT - 2) / 3;
+ mMaxActiveJobs = (MAX_JOB_CONTEXTS_COUNT - FG_JOB_CONTEXTS_COUNT) / 3;
break;
case ProcessStats.ADJ_MEM_FACTOR_CRITICAL:
mMaxActiveJobs = 1;
break;
default:
- mMaxActiveJobs = MAX_JOB_CONTEXTS_COUNT - 2;
+ mMaxActiveJobs = MAX_JOB_CONTEXTS_COUNT - FG_JOB_CONTEXTS_COUNT;
break;
}
@@ -1134,7 +1179,9 @@
if (!mActiveServices.get(i).executeRunnableJob(pendingJob)) {
Slog.d(TAG, "Error executing " + pendingJob);
}
- mPendingJobs.remove(pendingJob);
+ if (mPendingJobs.remove(pendingJob)) {
+ mJobPackageTracker.noteNonpending(pendingJob);
+ }
}
}
if (!preservePreferredUid) {
@@ -1444,6 +1491,8 @@
pw.print(": "); pw.println(mUidPriorityOverride.valueAt(i));
}
pw.println();
+ mJobPackageTracker.dump(pw, "");
+ pw.println();
pw.println("Pending queue:");
for (int i=0; i<mPendingJobs.size(); i++) {
JobStatus job = mPendingJobs.get(i);
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 4239248..4fd1350 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -105,6 +105,7 @@
private final Context mContext;
private final Object mLock;
private final IBatteryStats mBatteryStats;
+ private final JobPackageTracker mJobPackageTracker;
private PowerManager.WakeLock mWakeLock;
// Execution state.
@@ -136,16 +137,18 @@
/** Track when job will timeout. */
private long mTimeoutElapsed;
- JobServiceContext(JobSchedulerService service, IBatteryStats batteryStats, Looper looper) {
- this(service.getContext(), service.getLock(), batteryStats, service, looper);
+ JobServiceContext(JobSchedulerService service, IBatteryStats batteryStats,
+ JobPackageTracker tracker, Looper looper) {
+ this(service.getContext(), service.getLock(), batteryStats, tracker, service, looper);
}
@VisibleForTesting
JobServiceContext(Context context, Object lock, IBatteryStats batteryStats,
- JobCompletedListener completedListener, Looper looper) {
+ JobPackageTracker tracker, JobCompletedListener completedListener, Looper looper) {
mContext = context;
mLock = lock;
mBatteryStats = batteryStats;
+ mJobPackageTracker = tracker;
mCallbackHandler = new JobServiceHandler(looper);
mCompletedListener = completedListener;
mAvailable = true;
@@ -208,6 +211,7 @@
} catch (RemoteException e) {
// Whatever.
}
+ mJobPackageTracker.noteActive(job);
mAvailable = false;
return true;
}
@@ -580,6 +584,7 @@
return;
}
completedJob = mRunningJob;
+ mJobPackageTracker.noteInactive(completedJob);
try {
mBatteryStats.noteJobFinish(mRunningJob.getBatteryName(),
mRunningJob.getSourceUid());
diff --git a/services/core/java/com/android/server/job/controllers/AppIdleController.java b/services/core/java/com/android/server/job/controllers/AppIdleController.java
index d8490d4..02bc36ca 100644
--- a/services/core/java/com/android/server/job/controllers/AppIdleController.java
+++ b/services/core/java/com/android/server/job/controllers/AppIdleController.java
@@ -22,6 +22,7 @@
import com.android.server.LocalServices;
import com.android.server.job.JobSchedulerService;
+import com.android.server.job.JobStore;
import com.android.server.job.StateChangedListener;
import java.io.PrintWriter;
@@ -41,10 +42,52 @@
// Singleton factory
private static Object sCreationLock = new Object();
private static volatile AppIdleController sController;
- final ArrayList<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
+ private final JobSchedulerService mJobSchedulerService;
private final UsageStatsManagerInternal mUsageStatsInternal;
boolean mAppIdleParoleOn;
+ final class GlobalUpdateFunc implements JobStore.JobStatusFunctor {
+ boolean mChanged;
+
+ @Override public void process(JobStatus jobStatus) {
+ String packageName = jobStatus.getSourcePackageName();
+ final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
+ jobStatus.getSourceUid(), jobStatus.getSourceUserId());
+ if (DEBUG) {
+ Slog.d(LOG_TAG, "Setting idle state of " + packageName + " to " + appIdle);
+ }
+ if (jobStatus.setAppNotIdleConstraintSatisfied(!appIdle)) {
+ mChanged = true;
+ }
+ }
+ };
+
+ final static class PackageUpdateFunc implements JobStore.JobStatusFunctor {
+ final int mUserId;
+ final String mPackage;
+ final boolean mIdle;
+ boolean mChanged;
+
+ PackageUpdateFunc(int userId, String pkg, boolean idle) {
+ mUserId = userId;
+ mPackage = pkg;
+ mIdle = idle;
+ }
+
+ @Override public void process(JobStatus jobStatus) {
+ if (jobStatus.getSourcePackageName().equals(mPackage)
+ && jobStatus.getSourceUserId() == mUserId) {
+ if (jobStatus.setAppNotIdleConstraintSatisfied(!mIdle)) {
+ if (DEBUG) {
+ Slog.d(LOG_TAG, "App Idle state changed, setting idle state of "
+ + mPackage + " to " + mIdle);
+ }
+ mChanged = true;
+ }
+ }
+ }
+ };
+
public static AppIdleController get(JobSchedulerService service) {
synchronized (sCreationLock) {
if (sController == null) {
@@ -55,9 +98,9 @@
}
}
- private AppIdleController(StateChangedListener stateChangedListener, Context context,
- Object lock) {
- super(stateChangedListener, context, lock);
+ private AppIdleController(JobSchedulerService service, Context context, Object lock) {
+ super(service, context, lock);
+ mJobSchedulerService = service;
mUsageStatsInternal = LocalServices.getService(UsageStatsManagerInternal.class);
mAppIdleParoleOn = mUsageStatsInternal.isAppIdleParoleOn();
mUsageStatsInternal.addAppIdleStateChangeListener(new AppIdleStateChangeListener());
@@ -65,7 +108,6 @@
@Override
public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
- mTrackedTasks.add(jobStatus);
String packageName = jobStatus.getSourcePackageName();
final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
jobStatus.getSourceUid(), jobStatus.getSourceUserId());
@@ -78,19 +120,20 @@
@Override
public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob, boolean forUpdate) {
- mTrackedTasks.remove(jobStatus);
}
@Override
- public void dumpControllerStateLocked(PrintWriter pw) {
+ public void dumpControllerStateLocked(final PrintWriter pw) {
pw.println("AppIdle");
pw.println("Parole On: " + mAppIdleParoleOn);
- for (JobStatus task : mTrackedTasks) {
- pw.print(task.getSourcePackageName());
- pw.print(":runnable="
- + ((task.satisfiedConstraints&JobStatus.CONSTRAINT_APP_NOT_IDLE) != 0));
- pw.print(", ");
- }
+ mJobSchedulerService.getJobStore().forEachJob(new JobStore.JobStatusFunctor() {
+ @Override public void process(JobStatus jobStatus) {
+ pw.print(" ");
+ pw.print(jobStatus.getSourcePackageName());
+ pw.print(": runnable=");
+ pw.println((jobStatus.satisfiedConstraints&JobStatus.CONSTRAINT_APP_NOT_IDLE) != 0);
+ }
+ });
pw.println();
}
@@ -102,16 +145,10 @@
return;
}
mAppIdleParoleOn = isAppIdleParoleOn;
- for (JobStatus task : mTrackedTasks) {
- String packageName = task.getSourcePackageName();
- final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
- task.getSourceUid(), task.getSourceUserId());
- if (DEBUG) {
- Slog.d(LOG_TAG, "Setting idle state of " + packageName + " to " + appIdle);
- }
- if (task.setAppNotIdleConstraintSatisfied(!appIdle)) {
- changed = true;
- }
+ GlobalUpdateFunc update = new GlobalUpdateFunc();
+ mJobSchedulerService.getJobStore().forEachJob(update);
+ if (update.mChanged) {
+ changed = true;
}
}
if (changed) {
@@ -128,17 +165,10 @@
if (mAppIdleParoleOn) {
return;
}
- for (JobStatus task : mTrackedTasks) {
- if (task.getSourcePackageName().equals(packageName)
- && task.getSourceUserId() == userId) {
- if (task.setAppNotIdleConstraintSatisfied(!idle)) {
- if (DEBUG) {
- Slog.d(LOG_TAG, "App Idle state changed, setting idle state of "
- + packageName + " to " + idle);
- }
- changed = true;
- }
- }
+ PackageUpdateFunc update = new PackageUpdateFunc(userId, packageName, idle);
+ mJobSchedulerService.getJobStore().forEachJob(update);
+ if (update.mChanged) {
+ changed = true;
}
}
if (changed) {
diff --git a/services/core/java/com/android/server/job/controllers/ContentObserverController.java b/services/core/java/com/android/server/job/controllers/ContentObserverController.java
index b2f1958..c5b1a3d 100644
--- a/services/core/java/com/android/server/job/controllers/ContentObserverController.java
+++ b/services/core/java/com/android/server/job/controllers/ContentObserverController.java
@@ -21,6 +21,7 @@
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
+import android.util.TimeUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -46,12 +47,17 @@
*/
private static final int MAX_URIS_REPORTED = 50;
+ /**
+ * At this point we consider it urgent to schedule the job ASAP.
+ */
+ private static final int URIS_URGENT_THRESHOLD = 40;
+
private static final Object sCreationLock = new Object();
private static volatile ContentObserverController sController;
final private List<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
ArrayMap<Uri, ObserverInstance> mObservers = new ArrayMap<>();
- final Handler mHandler = new Handler();
+ final Handler mHandler;
public static ContentObserverController get(JobSchedulerService taskManagerService) {
synchronized (sCreationLock) {
@@ -72,6 +78,7 @@
private ContentObserverController(StateChangedListener stateChangedListener, Context context,
Object lock) {
super(stateChangedListener, context, lock);
+ mHandler = new Handler(context.getMainLooper());
}
@Override
@@ -113,6 +120,11 @@
taskStatus.changedUris = null;
taskStatus.setContentTriggerConstraintSatisfied(havePendingUris);
}
+ if (lastJob != null && lastJob.contentObserverJobInstance != null) {
+ // And now we can detach the instance state from the last job.
+ lastJob.contentObserverJobInstance.detachLocked();
+ lastJob.contentObserverJobInstance = null;
+ }
}
@Override
@@ -133,30 +145,33 @@
boolean forUpdate) {
if (taskStatus.hasContentTriggerConstraint()) {
if (taskStatus.contentObserverJobInstance != null) {
- if (incomingJob != null && taskStatus.contentObserverJobInstance != null
- && taskStatus.contentObserverJobInstance.mChangedAuthorities != null) {
- // We are stopping this job, but it is going to be replaced by this given
- // incoming job. We want to propagate our state over to it, so we don't
- // lose any content changes that had happend since the last one started.
- // If there is a previous job associated with the new job, propagate over
- // any pending content URI trigger reports.
- if (incomingJob.contentObserverJobInstance == null) {
- incomingJob.contentObserverJobInstance = new JobInstance(incomingJob);
+ taskStatus.contentObserverJobInstance.unscheduleLocked();
+ if (incomingJob != null) {
+ if (taskStatus.contentObserverJobInstance != null
+ && taskStatus.contentObserverJobInstance.mChangedAuthorities != null) {
+ // We are stopping this job, but it is going to be replaced by this given
+ // incoming job. We want to propagate our state over to it, so we don't
+ // lose any content changes that had happend since the last one started.
+ // If there is a previous job associated with the new job, propagate over
+ // any pending content URI trigger reports.
+ if (incomingJob.contentObserverJobInstance == null) {
+ incomingJob.contentObserverJobInstance = new JobInstance(incomingJob);
+ }
+ incomingJob.contentObserverJobInstance.mChangedAuthorities
+ = taskStatus.contentObserverJobInstance.mChangedAuthorities;
+ incomingJob.contentObserverJobInstance.mChangedUris
+ = taskStatus.contentObserverJobInstance.mChangedUris;
+ taskStatus.contentObserverJobInstance.mChangedAuthorities = null;
+ taskStatus.contentObserverJobInstance.mChangedUris = null;
}
- incomingJob.contentObserverJobInstance.mChangedAuthorities
- = taskStatus.contentObserverJobInstance.mChangedAuthorities;
- incomingJob.contentObserverJobInstance.mChangedUris
- = taskStatus.contentObserverJobInstance.mChangedUris;
- taskStatus.contentObserverJobInstance.mChangedAuthorities = null;
- taskStatus.contentObserverJobInstance.mChangedUris = null;
+ // We won't detach the content observers here, because we want to
+ // allow them to continue monitoring so we don't miss anything... and
+ // since we are giving an incomingJob here, we know this will be
+ // immediately followed by a start tracking of that job.
} else {
- // We won't do this reset if being called for an update, because
- // we know it will be immediately followed by maybeStartTrackingJobLocked...
- // and we don't want to lose any content changes in-between.
- if (taskStatus.contentObserverJobInstance != null) {
- taskStatus.contentObserverJobInstance.detach();
- taskStatus.contentObserverJobInstance = null;
- }
+ // But here there is no incomingJob, so nothing coming up, so time to detach.
+ taskStatus.contentObserverJobInstance.detachLocked();
+ taskStatus.contentObserverJobInstance = null;
}
}
mTrackedTasks.remove(taskStatus);
@@ -177,9 +192,9 @@
}
}
- class ObserverInstance extends ContentObserver {
+ final class ObserverInstance extends ContentObserver {
final Uri mUri;
- final ArrayList<JobInstance> mJobs = new ArrayList<>();
+ final ArraySet<JobInstance> mJobs = new ArraySet<>();
public ObserverInstance(Handler handler, Uri uri) {
super(handler);
@@ -188,11 +203,10 @@
@Override
public void onChange(boolean selfChange, Uri uri) {
- boolean reportChange = false;
synchronized (mLock) {
final int N = mJobs.size();
for (int i=0; i<N; i++) {
- JobInstance inst = mJobs.get(i);
+ JobInstance inst = mJobs.valueAt(i);
if (inst.mChangedUris == null) {
inst.mChangedUris = new ArraySet<>();
}
@@ -203,26 +217,38 @@
inst.mChangedAuthorities = new ArraySet<>();
}
inst.mChangedAuthorities.add(uri.getAuthority());
- if (inst.mJobStatus.setContentTriggerConstraintSatisfied(true)) {
- reportChange = true;
- }
+ inst.scheduleLocked();
}
}
- // Let the scheduler know that state has changed. This may or may not result in an
- // execution.
- if (reportChange) {
- mStateChangedListener.onControllerStateChanged();
- }
}
}
- class JobInstance extends ArrayList<ObserverInstance> {
- private final JobStatus mJobStatus;
- private ArraySet<Uri> mChangedUris;
- private ArraySet<String> mChangedAuthorities;
+ static final class TriggerRunnable implements Runnable {
+ final JobInstance mInstance;
+
+ TriggerRunnable(JobInstance instance) {
+ mInstance = instance;
+ }
+
+ @Override public void run() {
+ mInstance.trigger();
+ }
+ }
+
+ final class JobInstance {
+ final ArrayList<ObserverInstance> mMyObservers = new ArrayList<>();
+ final JobStatus mJobStatus;
+ final Runnable mExecuteRunner;
+ final Runnable mTimeoutRunner;
+ ArraySet<Uri> mChangedUris;
+ ArraySet<String> mChangedAuthorities;
+
+ boolean mTriggerPending;
JobInstance(JobStatus jobStatus) {
mJobStatus = jobStatus;
+ mExecuteRunner = new TriggerRunnable(this);
+ mTimeoutRunner = new TriggerRunnable(this);
final JobInfo.TriggerContentUri[] uris = jobStatus.getJob().getTriggerContentUris();
if (uris != null) {
for (JobInfo.TriggerContentUri uri : uris) {
@@ -238,15 +264,54 @@
obs);
}
obs.mJobs.add(this);
- add(obs);
+ mMyObservers.add(obs);
}
}
}
- void detach() {
- final int N = size();
+ void trigger() {
+ boolean reportChange = false;
+ synchronized (mLock) {
+ if (mTriggerPending) {
+ if (mJobStatus.setContentTriggerConstraintSatisfied(true)) {
+ reportChange = true;
+ }
+ unscheduleLocked();
+ }
+ }
+ // Let the scheduler know that state has changed. This may or may not result in an
+ // execution.
+ if (reportChange) {
+ mStateChangedListener.onControllerStateChanged();
+ }
+ }
+
+ void scheduleLocked() {
+ if (!mTriggerPending) {
+ mTriggerPending = true;
+ mHandler.postDelayed(mTimeoutRunner, mJobStatus.getTriggerContentMaxDelay());
+ }
+ mHandler.removeCallbacks(mExecuteRunner);
+ if (mChangedUris.size() >= URIS_URGENT_THRESHOLD) {
+ // If we start getting near the limit, GO NOW!
+ mHandler.post(mExecuteRunner);
+ } else {
+ mHandler.postDelayed(mExecuteRunner, mJobStatus.getTriggerContentUpdateDelay());
+ }
+ }
+
+ void unscheduleLocked() {
+ if (mTriggerPending) {
+ mHandler.removeCallbacks(mExecuteRunner);
+ mHandler.removeCallbacks(mTimeoutRunner);
+ mTriggerPending = false;
+ }
+ }
+
+ void detachLocked() {
+ final int N = mMyObservers.size();
for (int i=0; i<N; i++) {
- final ObserverInstance obs = get(i);
+ final ObserverInstance obs = mMyObservers.get(i);
obs.mJobs.remove(this);
if (obs.mJobs.size() == 0) {
mContext.getContentResolver().unregisterContentObserver(obs);
@@ -259,39 +324,54 @@
@Override
public void dumpControllerStateLocked(PrintWriter pw) {
pw.println("Content.");
+ boolean printed = false;
Iterator<JobStatus> it = mTrackedTasks.iterator();
- if (it.hasNext()) {
- pw.print(String.valueOf(it.next().hashCode()));
- }
while (it.hasNext()) {
- pw.print("," + String.valueOf(it.next().hashCode()));
+ if (!printed) {
+ pw.print(" ");
+ printed = true;
+ } else {
+ pw.print(",");
+ }
+ pw.print(System.identityHashCode(it.next()));
}
- pw.println();
+ if (printed) {
+ pw.println();
+ }
int N = mObservers.size();
if (N > 0) {
- pw.println("URIs:");
+ pw.println(" Observers:");
for (int i = 0; i < N; i++) {
ObserverInstance obs = mObservers.valueAt(i);
- pw.print(" ");
- pw.print(mObservers.keyAt(i));
- pw.println(":");
pw.print(" ");
- pw.println(obs);
- pw.println(" Jobs:");
+ pw.print(mObservers.keyAt(i));
+ pw.print(" (");
+ pw.print(System.identityHashCode(obs));
+ pw.println("):");
+ pw.println(" Jobs:");
int M = obs.mJobs.size();
for (int j=0; j<M; j++) {
- JobInstance inst = obs.mJobs.get(j);
- pw.print(" ");
- pw.print(inst.hashCode());
+ JobInstance inst = obs.mJobs.valueAt(j);
+ pw.print(" ");
+ pw.print(System.identityHashCode(inst.mJobStatus));
if (inst.mChangedAuthorities != null) {
pw.println(":");
- pw.println(" Changed Authorities:");
+ if (inst.mTriggerPending) {
+ pw.print(" Trigger pending: update=");
+ TimeUtils.formatDuration(
+ inst.mJobStatus.getTriggerContentUpdateDelay(), pw);
+ pw.print(", max=");
+ TimeUtils.formatDuration(
+ inst.mJobStatus.getTriggerContentMaxDelay(), pw);
+ pw.println();
+ }
+ pw.println(" Changed Authorities:");
for (int k=0; k<inst.mChangedAuthorities.size(); k++) {
pw.print(" ");
pw.println(inst.mChangedAuthorities.valueAt(k));
}
if (inst.mChangedUris != null) {
- pw.println(" Changed URIs:");
+ pw.println(" Changed URIs:");
for (int k = 0; k<inst.mChangedUris.size(); k++) {
pw.print(" ");
pw.println(inst.mChangedUris.valueAt(k));
diff --git a/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java b/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java
index 64887e8..fe563d2 100644
--- a/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java
+++ b/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java
@@ -28,6 +28,7 @@
import com.android.server.DeviceIdleController;
import com.android.server.LocalServices;
import com.android.server.job.JobSchedulerService;
+import com.android.server.job.JobStore;
import com.android.server.job.StateChangedListener;
import java.io.PrintWriter;
@@ -45,9 +46,9 @@
// Singleton factory
private static Object sCreationLock = new Object();
- final ArrayList<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
private static DeviceIdleJobsController sController;
+ private final JobSchedulerService mJobSchedulerService;
private final PowerManager mPowerManager;
private final DeviceIdleController.LocalService mLocalDeviceIdleController;
@@ -57,6 +58,12 @@
private boolean mDeviceIdleMode;
private int[] mDeviceIdleWhitelistAppIds;
+ final JobStore.JobStatusFunctor mUpdateFunctor = new JobStore.JobStatusFunctor() {
+ @Override public void process(JobStatus jobStatus) {
+ updateTaskStateLocked(jobStatus);
+ }
+ };
+
/**
* Returns a singleton for the DeviceIdleJobsController
*/
@@ -87,10 +94,11 @@
}
};
- private DeviceIdleJobsController(StateChangedListener stateChangedListener, Context context,
+ private DeviceIdleJobsController(JobSchedulerService jobSchedulerService, Context context,
Object lock) {
- super(stateChangedListener, context, lock);
+ super(jobSchedulerService, context, lock);
+ mJobSchedulerService = jobSchedulerService;
// Register for device idle mode changes
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mLocalDeviceIdleController =
@@ -115,9 +123,7 @@
}
mDeviceIdleMode = enabled;
if (LOG_DEBUG) Slog.d(LOG_TAG, "mDeviceIdleMode=" + mDeviceIdleMode);
- for (JobStatus task : mTrackedTasks) {
- updateTaskStateLocked(task);
- }
+ mJobSchedulerService.getJobStore().forEachJob(mUpdateFunctor);
}
// Inform the job scheduler service about idle mode changes
if (changed) {
@@ -160,25 +166,26 @@
@Override
public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
synchronized (mLock) {
- mTrackedTasks.add(jobStatus);
updateTaskStateLocked(jobStatus);
}
}
@Override
public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob, boolean forUpdate) {
- mTrackedTasks.remove(jobStatus);
}
@Override
- public void dumpControllerStateLocked(PrintWriter pw) {
+ public void dumpControllerStateLocked(final PrintWriter pw) {
pw.println("DeviceIdleJobsController");
- for (JobStatus task : mTrackedTasks) {
- pw.print(task.getSourcePackageName());
- pw.print(":runnable="
- + ((task.satisfiedConstraints & JobStatus.CONSTRAINT_DEVICE_NOT_DOZING) != 0));
- pw.print(", ");
- }
+ mJobSchedulerService.getJobStore().forEachJob(new JobStore.JobStatusFunctor() {
+ @Override public void process(JobStatus jobStatus) {
+ pw.print(" ");
+ pw.print(jobStatus.getSourcePackageName());
+ pw.print(": runnable=");
+ pw.println((jobStatus.satisfiedConstraints
+ & JobStatus.CONSTRAINT_DEVICE_NOT_DOZING) != 0);
+ }
+ });
pw.println();
}
}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 39905d8..dd70758 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -61,6 +61,18 @@
// Full override: ignore all constraints including API-affecting like connectivity
public static final int OVERRIDE_FULL = 2;
+ /** If not specified, trigger update delay is 10 seconds. */
+ public static final long DEFAULT_TRIGGER_UPDATE_DELAY = 10*1000;
+
+ /** The minimum possible update delay is 1/2 second. */
+ public static final long MIN_TRIGGER_UPDATE_DELAY = 500;
+
+ /** If not specified, trigger maxumum delay is 2 minutes. */
+ public static final long DEFAULT_TRIGGER_MAX_DELAY = 2*60*1000;
+
+ /** The minimum possible update delay is 1 second. */
+ public static final long MIN_TRIGGER_MAX_DELAY = 1000;
+
final JobInfo job;
/** Uid of the package requesting this job. */
final int callingUid;
@@ -320,6 +332,22 @@
return (requiredConstraints&CONSTRAINT_CONTENT_TRIGGER) != 0;
}
+ public long getTriggerContentUpdateDelay() {
+ long time = job.getTriggerContentUpdateDelay();
+ if (time < 0) {
+ return DEFAULT_TRIGGER_UPDATE_DELAY;
+ }
+ return Math.max(time, MIN_TRIGGER_UPDATE_DELAY);
+ }
+
+ public long getTriggerContentMaxDelay() {
+ long time = job.getTriggerContentMaxDelay();
+ if (time < 0) {
+ return DEFAULT_TRIGGER_MAX_DELAY;
+ }
+ return Math.max(time, MIN_TRIGGER_MAX_DELAY);
+ }
+
public boolean isPersisted() {
return job.isPersisted();
}
@@ -540,6 +568,16 @@
pw.print(Integer.toHexString(trig.getFlags()));
pw.print(' '); pw.println(trig.getUri());
}
+ if (job.getTriggerContentUpdateDelay() >= 0) {
+ pw.print(prefix); pw.print(" Trigger update delay: ");
+ TimeUtils.formatDuration(job.getTriggerContentUpdateDelay(), pw);
+ pw.println();
+ }
+ if (job.getTriggerContentMaxDelay() >= 0) {
+ pw.print(prefix); pw.print(" Trigger max delay: ");
+ TimeUtils.formatDuration(job.getTriggerContentMaxDelay(), pw);
+ pw.println();
+ }
}
if (job.getNetworkType() != JobInfo.NETWORK_TYPE_NONE) {
pw.print(prefix); pw.print(" Network type: "); pw.println(job.getNetworkType());
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 92b59965..1fb260d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -7085,9 +7085,6 @@
pkgs = PackageManagerServiceUtils.getPackagesForDexopt(mPackages.values(), this);
}
- UsageStatsManager usageMgr =
- (UsageStatsManager) mContext.getSystemService(Context.USAGE_STATS_SERVICE);
-
int curr = 0;
int total = pkgs.size();
for (PackageParser.Package pkg : pkgs) {
@@ -7100,13 +7097,6 @@
continue;
}
- if (!causeFirstBoot && usageMgr.isAppInactive(pkg.packageName)) {
- if (DEBUG_DEXOPT) {
- Log.i(TAG, "Skipping update of of idle app " + pkg.packageName);
- }
- continue;
- }
-
if (DEBUG_DEXOPT) {
Log.i(TAG, "Extracting app " + curr + " of " + total + ": " + pkg.packageName);
}
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index aa10c08..a6350fe 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -92,7 +92,7 @@
* MAC_PERMISSIONS class variable which is set at class load time which itself
* is based on the USE_OVERRIDE_POLICY class variable. For further guidance on
* the proper structure of a mac_permissions.xml file consult the source code
- * located at external/sepolicy/mac_permissions.xml.
+ * located at system/sepolicy/mac_permissions.xml.
*
* @return boolean indicating if policy was correctly loaded. A value of false
* typically indicates a structural problem with the xml or incorrectly
@@ -373,7 +373,7 @@
* {@link Policy#getMatchedSeinfo} method. To create an instance of this use the
* {@link PolicyBuilder} pattern class, where each instance is validated against a set
* of invariants before being built and returned. Each instance can be guaranteed to
- * hold one valid policy stanza as outlined in the external/sepolicy/mac_permissions.xml
+ * hold one valid policy stanza as outlined in the system/sepolicy/mac_permissions.xml
* file.
* <p>
* The following is an example of how to use {@link Policy.PolicyBuilder} to create a
@@ -519,7 +519,7 @@
* A nested builder class to create {@link Policy} instances. A {@link Policy}
* class instance represents one valid policy stanza found in a mac_permissions.xml
* file. A valid policy stanza is defined to be a signer stanza which obeys the rules
- * outlined in external/sepolicy/mac_permissions.xml. The {@link #build} method
+ * outlined in system/sepolicy/mac_permissions.xml. The {@link #build} method
* ensures a set of invariants are upheld enforcing the correct stanza structure
* before returning a valid Policy object.
*/
diff --git a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
index 27077f2..553c5de 100644
--- a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
@@ -80,8 +80,6 @@
.getInteger(R.integer.config_immersive_mode_confirmation_panic);
mWindowManager = (WindowManager)
mContext.getSystemService(Context.WINDOW_SERVICE);
- mVrManager = (IVrManager) IVrManager.Stub.asInterface(
- ServiceManager.getService(VrManagerService.VR_MANAGER_BINDER_SERVICE));
}
private long getNavBarExitDuration() {
@@ -121,11 +119,18 @@
private boolean getVrMode() {
boolean vrMode = false;
- try {
- vrMode = mVrManager.getVrModeState();
- } catch (RemoteException ex) { }
+ if (mVrManager == null) {
+ // lazily grab this service since it may not be available at construction time
+ mVrManager = (IVrManager) IVrManager.Stub.asInterface(
+ ServiceManager.getService(VrManagerService.VR_MANAGER_BINDER_SERVICE));
+ }
+ if (mVrManager != null) {
+ try {
+ vrMode = mVrManager.getVrModeState();
+ } catch (RemoteException ex) { }
+ }
return vrMode;
- }
+ }
public void immersiveModeChanged(String pkg, boolean isImmersiveMode,
boolean userSetupComplete) {
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 984fb76..3c84fc2 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -974,7 +974,6 @@
public void register(Context context) {
IntentFilter filter = new IntentFilter();
filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
- filter.addAction(Intent.ACTION_USER_PRESENT);
filter.addAction(Intent.ACTION_USER_ADDED);
filter.addAction(Intent.ACTION_USER_REMOVED);
context.registerReceiverAsUser(this,
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index ca1a7ac..10e30ed 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -128,6 +128,8 @@
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
mService.systemReady();
+ } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
+ mService.switchUser(UserHandle.USER_SYSTEM, null);
}
}
@@ -850,9 +852,6 @@
Slog.i(TAG, "Nondefault wallpaper component; gracefully ignoring");
}
}
- switchWallpaper(wallpaper, null);
- wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
- wallpaper.wallpaperObserver.startWatching();
IntentFilter userFilter = new IntentFilter();
userFilter.addAction(Intent.ACTION_USER_REMOVED);
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
index df5d027..e17ea49 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
@@ -245,8 +245,16 @@
synchronized(mLock) {
try {
newPackage = findPreferredWebViewPackage();
- if (mCurrentWebViewPackage != null)
+ if (mCurrentWebViewPackage != null) {
oldProviderName = mCurrentWebViewPackage.packageName;
+ if (changedState == WebViewUpdateService.PACKAGE_CHANGED
+ && newPackage.packageName.equals(oldProviderName)) {
+ // If we don't change package name we should only rerun the
+ // preparation phase if the current package has been replaced
+ // (not if it has been enabled/disabled).
+ return;
+ }
+ }
// Only trigger update actions if the updated package is the one
// that will be used, or the one that was in use before the
// update, or if we haven't seen a valid WebView package before.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 57f38d1..0a0f0f0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -18,6 +18,7 @@
import android.Manifest;
import android.animation.ValueAnimator;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManagerInternal;
@@ -153,6 +154,8 @@
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.net.Socket;
import java.text.DateFormat;
import java.util.ArrayList;
@@ -332,6 +335,14 @@
private static final String PROPERTY_BUILD_DATE_UTC = "ro.build.date.utc";
+ // Enums for animation scale update types.
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({WINDOW_ANIMATION_SCALE, TRANSITION_ANIMATION_SCALE, ANIMATION_DURATION_SCALE})
+ private @interface UpdateAnimationScaleMode {};
+ private static final int WINDOW_ANIMATION_SCALE = 0;
+ private static final int TRANSITION_ANIMATION_SCALE = 1;
+ private static final int ANIMATION_DURATION_SCALE = 2;
+
final private KeyguardDisableHandler mKeyguardDisableHandler;
final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@@ -613,18 +624,42 @@
private final class SettingsObserver extends ContentObserver {
private final Uri mDisplayInversionEnabledUri =
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
+ private final Uri mWindowAnimationScaleUri =
+ Settings.Global.getUriFor(Settings.Global.WINDOW_ANIMATION_SCALE);
+ private final Uri mTransitionAnimationScaleUri =
+ Settings.Global.getUriFor(Settings.Global.TRANSITION_ANIMATION_SCALE);
+ private final Uri mAnimationDurationScaleUri =
+ Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE);
public SettingsObserver() {
super(new Handler());
ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(mDisplayInversionEnabledUri, false, this,
UserHandle.USER_ALL);
+ resolver.registerContentObserver(mWindowAnimationScaleUri, false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(mTransitionAnimationScaleUri, false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(mAnimationDurationScaleUri, false, this,
+ UserHandle.USER_ALL);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
if (mDisplayInversionEnabledUri.equals(uri)) {
updateCircularDisplayMaskIfNeeded();
+ } else {
+ @UpdateAnimationScaleMode
+ final int mode;
+ if (uri.equals(mWindowAnimationScaleUri)) {
+ mode = WINDOW_ANIMATION_SCALE;
+ } else if (uri.equals(mTransitionAnimationScaleUri)) {
+ mode = TRANSITION_ANIMATION_SCALE;
+ } else { // uri.equals(mAnimationDurationScaleUri)
+ mode = ANIMATION_DURATION_SCALE;
+ }
+ Message m = mH.obtainMessage(H.UPDATE_ANIMATION_SCALE, mode, 0);
+ mH.sendMessage(m);
}
}
}
@@ -3905,16 +3940,6 @@
return;
}
- if (transferStartingWindow(transferFrom, wtoken)) {
- return;
- }
-
- // There is no existing starting window, and the caller doesn't
- // want us to create one, so that's it!
- if (!createIfNeeded) {
- return;
- }
-
// If this is a translucent window, then don't
// show a starting window -- the current effect (a full-screen
// opaque starting window that fades away to the real contents
@@ -3960,6 +3985,16 @@
}
}
+ if (transferStartingWindow(transferFrom, wtoken)) {
+ return;
+ }
+
+ // There is no existing starting window, and the caller doesn't
+ // want us to create one, so that's it!
+ if (!createIfNeeded) {
+ return;
+ }
+
if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating StartingData");
wtoken.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel,
labelRes, icon, logo, windowFlags);
@@ -5986,7 +6021,13 @@
"screenshotApplications()")) {
throw new SecurityException("Requires READ_FRAME_BUFFER permission");
}
- return screenshotApplicationsInner(appToken, displayId, width, height, false, frameScale);
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotApplications");
+ return screenshotApplicationsInner(appToken, displayId, width, height, false,
+ frameScale);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+ }
}
Bitmap screenshotApplicationsInner(IBinder appToken, int displayId, int width, int height,
@@ -7748,6 +7789,8 @@
public static final int NOTIFY_APP_TRANSITION_FINISHED = 49;
public static final int NOTIFY_STARTING_WINDOW_DRAWN = 50;
+ public static final int UPDATE_ANIMATION_SCALE = 51;
+
/**
* Used to denote that an integer field in a message will not be used.
*/
@@ -8030,6 +8073,36 @@
break;
}
+ case UPDATE_ANIMATION_SCALE: {
+ @UpdateAnimationScaleMode
+ final int mode = msg.arg1;
+ switch (mode) {
+ case WINDOW_ANIMATION_SCALE: {
+ mWindowAnimationScaleSetting = Settings.Global.getFloat(
+ mContext.getContentResolver(),
+ Settings.Global.WINDOW_ANIMATION_SCALE,
+ mWindowAnimationScaleSetting);
+ break;
+ }
+ case TRANSITION_ANIMATION_SCALE: {
+ mTransitionAnimationScaleSetting = Settings.Global.getFloat(
+ mContext.getContentResolver(),
+ Settings.Global.TRANSITION_ANIMATION_SCALE,
+ mTransitionAnimationScaleSetting);
+ break;
+ }
+ case ANIMATION_DURATION_SCALE: {
+ mAnimatorDurationScaleSetting = Settings.Global.getFloat(
+ mContext.getContentResolver(),
+ Settings.Global.ANIMATOR_DURATION_SCALE,
+ mAnimatorDurationScaleSetting);
+ dispatchNewAnimatorScaleLocked(null);
+ break;
+ }
+ }
+ break;
+ }
+
case FORCE_GC: {
synchronized (mWindowMap) {
// Since we're holding both mWindowMap and mAnimator we don't need to
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c48d7d1..8371cfe 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2410,8 +2410,8 @@
pw.print(prefix); pw.print("mToken="); pw.println(mToken);
pw.print(prefix); pw.print("mRootToken="); pw.println(mRootToken);
if (mAppToken != null) {
- pw.print(prefix); pw.print("mAppToken="); pw.print(mAppToken);
- pw.print(" isAnimatingWithSavedSurface()=");
+ pw.print(prefix); pw.print("mAppToken="); pw.println(mAppToken);
+ pw.print(prefix); pw.print(" isAnimatingWithSavedSurface()=");
pw.print(isAnimatingWithSavedSurface());
pw.print(" mAppDied=");pw.println(mAppDied);
}
@@ -2496,6 +2496,7 @@
pw.print(" content="); mContentInsets.printShortString(pw);
pw.print(" visible="); mVisibleInsets.printShortString(pw);
pw.print(" stable="); mStableInsets.printShortString(pw);
+ pw.print(" surface="); mAttrs.surfaceInsets.printShortString(pw);
pw.print(" outsets="); mOutsets.printShortString(pw);
pw.println();
pw.print(prefix); pw.print("Lst insets: overscan=");
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 140f381..0245513 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.ActivityManager.StackId;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
@@ -1032,7 +1033,7 @@
// relative to their containing frame. We need to offset the difference
// between the containing frame as used to calculate the crop and our
// bounds to compensate for this.
- if (mWin.isChildWindow() && mWin.layoutInParentFrame()) {
+ if (mWin.layoutInParentFrame()) {
mClipRect.offset( (mWin.mContainingFrame.left - mWin.mFrame.left),
mWin.mContainingFrame.top - mWin.mFrame.top );
}
@@ -1164,8 +1165,8 @@
final float scale = w.mInvGlobalScale;
mSystemDecorRect.left = (int) (mSystemDecorRect.left * scale - 0.5f);
mSystemDecorRect.top = (int) (mSystemDecorRect.top * scale - 0.5f);
- mSystemDecorRect.right = (int) ((mSystemDecorRect.right+1) * scale - 0.5f);
- mSystemDecorRect.bottom = (int) ((mSystemDecorRect.bottom+1) * scale - 0.5f);
+ mSystemDecorRect.right = (int) ((mSystemDecorRect.right + 1) * scale - 0.5f);
+ mSystemDecorRect.bottom = (int) ((mSystemDecorRect.bottom + 1) * scale - 0.5f);
}
}
@@ -1178,8 +1179,8 @@
return;
}
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Updating crop for window: " + w + ", " + "mLastCrop=" +
- mLastClipRect);
+ if (DEBUG_WINDOW_CROP) Slog.d(TAG,
+ "Updating crop win=" + w + " mLastCrop=" + mLastClipRect);
// Need to recompute a new system decor rect each time.
if (!w.isDefaultDisplay()) {
@@ -1204,8 +1205,8 @@
} else {
// Crop to the system decor specified by policy.
calculateSystemDecorRect();
- if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Applying decor to crop for " + w + ", mDecorFrame="
- + w.mDecorFrame + ", mSystemDecorRect=" + mSystemDecorRect);
+ if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Applying decor to crop win=" + w + " mDecorFrame="
+ + w.mDecorFrame + " mSystemDecorRect=" + mSystemDecorRect);
}
final boolean fullscreen = w.isFrameFullscreen(displayInfo);
@@ -1215,8 +1216,8 @@
// We use the clip rect as provided by the tranformation for non-fullscreen windows to
// avoid premature clipping with the system decor rect.
clipRect.set((mHasClipRect && !fullscreen) ? mClipRect : mSystemDecorRect);
- if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Initial clip rect: " + clipRect + ", mHasClipRect="
- + mHasClipRect + ", fullscreen=" + fullscreen);
+ if (DEBUG_WINDOW_CROP) Slog.d(TAG, "win=" + w + " Initial clip rect: " + clipRect
+ + " mHasClipRect=" + mHasClipRect + " fullscreen=" + fullscreen);
if (isFreeformResizing && !w.isChildWindow()) {
// For freeform resizing non child windows, we are using the big surface positioned
@@ -1243,7 +1244,8 @@
finalClipRect.setEmpty();
adjustCropToStackBounds(w, clipRect, finalClipRect, isFreeformResizing);
- if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Clip rect after stack adjustment=" + clipRect);
+ if (DEBUG_WINDOW_CROP) Slog.d(TAG,
+ "win=" + w + " Clip rect after stack adjustment=" + clipRect);
w.transformFromScreenToSurfaceSpace(clipRect);
@@ -1254,6 +1256,8 @@
}
void updateSurfaceWindowCrop(Rect clipRect, Rect finalClipRect, boolean recoveringMemory) {
+ if (DEBUG_WINDOW_CROP) Slog.d(TAG, "updateSurfaceWindowCrop: win=" + mWin
+ + " clipRect=" + clipRect + " finalClipRect=" + finalClipRect);
if (!clipRect.equals(mLastClipRect)) {
mLastClipRect.set(clipRect);
mSurfaceController.setCropInTransaction(clipRect, recoveringMemory);
@@ -1294,13 +1298,14 @@
final TaskStack stack = task.mStack;
stack.getDimBounds(mTmpStackBounds);
+ final Rect surfaceInsets = w.getAttrs().surfaceInsets;
// When we resize we use the big surface approach, which means we can't trust the
// window frame bounds anymore. Instead, the window will be placed at 0, 0, but to avoid
// hardcoding it, we use surface coordinates.
final int frameX = isFreeformResizing ? (int) mSurfaceController.getX() :
- w.mFrame.left + mWin.mXOffset - w.getAttrs().surfaceInsets.left;
+ w.mFrame.left + mWin.mXOffset - surfaceInsets.left;
final int frameY = isFreeformResizing ? (int) mSurfaceController.getY() :
- w.mFrame.top + mWin.mYOffset - w.getAttrs().surfaceInsets.top;
+ w.mFrame.top + mWin.mYOffset - surfaceInsets.top;
// If we are animating, we either apply the clip before applying all the animation
// transformation or after all the transformation.
@@ -1311,6 +1316,15 @@
if (useFinalClipRect) {
finalClipRect.set(mTmpStackBounds);
} else {
+ if (StackId.hasWindowShadow(stack.mStackId)
+ && !StackId.isTaskResizeAllowed(stack.mStackId)) {
+ // The windows in this stack display drop shadows and the fill the entire stack
+ // area. Adjust the stack bounds we will use to cropping take into account the
+ // offsets we use to display the drop shadow so it doesn't get cropped.
+ mTmpStackBounds.inset(-surfaceInsets.left, -surfaceInsets.top,
+ -surfaceInsets.right, -surfaceInsets.bottom);
+ }
+
clipRect.left = Math.max(0,
Math.max(mTmpStackBounds.left, frameX + clipRect.left) - frameX);
clipRect.top = Math.max(0,
@@ -1356,21 +1370,19 @@
// past where the system would have cropped us
mTmpClipRect.set(0, 0, mTmpSize.width(), mTmpSize.height());
mTmpFinalClipRect.setEmpty();
- updateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect, recoveringMemory);
} else {
mSurfaceController.setPositionInTransaction(mTmpSize.left, mTmpSize.top,
recoveringMemory);
- updateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect, recoveringMemory);
}
+ updateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect, recoveringMemory);
mSurfaceController.setMatrixInTransaction(mDsDx * w.mHScale * extraHScale,
mDtDx * w.mVScale * extraVScale,
mDsDy * w.mHScale * extraHScale,
mDtDy * w.mVScale * extraVScale, recoveringMemory);
mSurfaceResized = mSurfaceController.setSizeInTransaction(
- mTmpSize.width(), mTmpSize.height(),
- recoveringMemory);
+ mTmpSize.width(), mTmpSize.height(), recoveringMemory);
if (mSurfaceResized) {
mReportSurfaceResized = true;
@@ -1775,7 +1787,7 @@
pw.print(prefix); pw.print("mAnimating="); pw.print(mAnimating);
pw.print(" mLocalAnimating="); pw.print(mLocalAnimating);
pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance);
- pw.print(" mAnimation="); pw.println(mAnimation);
+ pw.print(" mAnimation="); pw.print(mAnimation);
pw.print(" mStackClip="); pw.println(mStackClip);
}
if (mHasTransformation || mHasLocalTransformation) {
@@ -1793,9 +1805,9 @@
pw.print(prefix); pw.print(" mLastHidden="); pw.println(mLastHidden);
pw.print(prefix); pw.print("mSystemDecorRect="); mSystemDecorRect.printShortString(pw);
pw.print(" last="); mLastSystemDecorRect.printShortString(pw);
- if (mHasClipRect) {
- pw.print(" mLastClipRect="); mLastClipRect.printShortString(pw);
- }
+ pw.print(" mHasClipRect="); pw.print(mHasClipRect);
+ pw.print(" mLastClipRect="); mLastClipRect.printShortString(pw);
+
if (!mLastFinalClipRect.isEmpty()) {
pw.print(" mLastFinalClipRect="); mLastFinalClipRect.printShortString(pw);
}
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 93eb82f..058b631 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -1165,7 +1165,7 @@
static jobject translate_gnss_clock(JNIEnv* env, GnssClock* clock) {
JavaObject object(env, "android/location/GnssClock");
- GpsClockFlags flags = clock->flags;
+ GnssClockFlags flags = clock->flags;
SET_IF(GNSS_CLOCK_HAS_LEAP_SECOND,
LeapSecond,
@@ -1237,9 +1237,10 @@
static jobject translate_gnss_measurement(JNIEnv* env,
GnssMeasurement* measurement) {
JavaObject object(env, "android/location/GnssMeasurement");
- GpsMeasurementFlags flags = measurement->flags;
- SET(Svid, measurement->svid);
+ GnssMeasurementFlags flags = measurement->flags;
+
+ SET(Svid, static_cast<int32_t>(measurement->svid));
SET(ConstellationType, static_cast<int32_t>(measurement->constellation));
SET(TimeOffsetNanos, measurement->time_offset_ns);
SET(State, static_cast<int32_t>(measurement->state));
@@ -1379,8 +1380,8 @@
ALOGE("Invalid data provided to gps_measurement_callback");
return;
}
- if (data->size != sizeof(GpsData)) {
- ALOGE("Invalid GpsData size found in gps_measurement_callback, "
+ if (data->size != sizeof(GnssData)) {
+ ALOGE("Invalid GnssData size found in gnss_measurement_callback, "
"size=%zd",
data->size);
return;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 0454b00..d3d05f3 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -655,8 +655,8 @@
Bundle userRestrictions;
// Support text provided by the admin to display to the user.
- String shortSupportMessage = null;
- String longSupportMessage = null;
+ CharSequence shortSupportMessage = null;
+ CharSequence longSupportMessage = null;
// Background color of confirm credentials screen. Default: teal.
static final int DEF_ORGANIZATION_COLOR = Color.parseColor("#00796B");
@@ -870,12 +870,12 @@
}
if (!TextUtils.isEmpty(shortSupportMessage)) {
out.startTag(null, TAG_SHORT_SUPPORT_MESSAGE);
- out.text(shortSupportMessage);
+ out.text(shortSupportMessage.toString());
out.endTag(null, TAG_SHORT_SUPPORT_MESSAGE);
}
if (!TextUtils.isEmpty(longSupportMessage)) {
out.startTag(null, TAG_LONG_SUPPORT_MESSAGE);
- out.text(longSupportMessage);
+ out.text(longSupportMessage.toString());
out.endTag(null, TAG_LONG_SUPPORT_MESSAGE);
}
if (parentAdmin != null) {
@@ -8504,7 +8504,7 @@
}
@Override
- public void setShortSupportMessage(@NonNull ComponentName who, String message) {
+ public void setShortSupportMessage(@NonNull ComponentName who, CharSequence message) {
if (!mHasFeature) {
return;
}
@@ -8521,7 +8521,7 @@
}
@Override
- public String getShortSupportMessage(@NonNull ComponentName who) {
+ public CharSequence getShortSupportMessage(@NonNull ComponentName who) {
if (!mHasFeature) {
return null;
}
@@ -8534,7 +8534,7 @@
}
@Override
- public void setLongSupportMessage(@NonNull ComponentName who, String message) {
+ public void setLongSupportMessage(@NonNull ComponentName who, CharSequence message) {
if (!mHasFeature) {
return;
}
@@ -8551,7 +8551,7 @@
}
@Override
- public String getLongSupportMessage(@NonNull ComponentName who) {
+ public CharSequence getLongSupportMessage(@NonNull ComponentName who) {
if (!mHasFeature) {
return null;
}
@@ -8564,7 +8564,7 @@
}
@Override
- public String getShortSupportMessageForUser(@NonNull ComponentName who, int userHandle) {
+ public CharSequence getShortSupportMessageForUser(@NonNull ComponentName who, int userHandle) {
if (!mHasFeature) {
return null;
}
@@ -8582,7 +8582,7 @@
}
@Override
- public String getLongSupportMessageForUser(@NonNull ComponentName who, int userHandle) {
+ public CharSequence getLongSupportMessageForUser(@NonNull ComponentName who, int userHandle) {
if (!mHasFeature) {
return null;
}
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index b6ad25b..c716cc8 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -536,6 +536,16 @@
delta = ProvisioningChange.LOST_PROVISIONING;
}
+ // Additionally:
+ //
+ // If the previous link properties had a global IPv6 address and an
+ // IPv6 default route then also consider the loss of that default route
+ // to be a loss of provisioning. See b/27962810.
+ if (oldLp.hasGlobalIPv6Address() && oldLp.hasIPv6DefaultRoute() &&
+ !newLp.hasIPv6DefaultRoute()) {
+ delta = ProvisioningChange.LOST_PROVISIONING;
+ }
+
return delta;
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 638b286..0bca628 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -3644,22 +3644,6 @@
}
/**
- * Returns the response of SIM Authentication through RIL for the default subscription.
- * Returns null if the Authentication hasn't been successful
- *
- * <p>Requires that the calling app has carrier privileges.
- * @see #hasCarrierPrivileges
- *
- * @param appType ICC application type (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx)
- * @param data authentication challenge data
- * @return the response of SIM Authentication, or null if not available
- * @hide
- */
- public String getIccSimChallengeResponse(int appType, String data) {
- return getIccAuthentication(getDefaultSubscription(), appType, AUTHTYPE_EAP_SIM, data);
- }
-
- /**
* Get P-CSCF address from PCO after data connection is established or modified.
* @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN
* @return array of P-CSCF address
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl b/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl
deleted file mode 100644
index 069fcbf..0000000
--- a/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony;
-
-import com.android.internal.telephony.ITelephonyDebugSubscriber;
-
-import android.os.Bundle;
-
-/**
- * Interface used to interact with the Telephony debug service.
- *
- * {@hide}
- */
-interface ITelephonyDebug {
-
- /**
- * Write telephony event
- * @param timestamp returned by System.currentTimeMillis()
- * @param phoneId for which event is written
- * @param tag constant defined in TelephonyEventLog
- * @param param1 optional
- * @param param2 optional
- * @param data optional
- */
- void writeEvent(long timestamp, int phoneId, int tag, int param1, int param2, in Bundle data);
-
- void subscribe(in ITelephonyDebugSubscriber subscriber);
- void unsubscribe(in ITelephonyDebugSubscriber subscriber);
-}
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl b/telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl
deleted file mode 100644
index 64eb0f1..0000000
--- a/telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl
+++ /dev/null
@@ -1,34 +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 com.android.internal.telephony;
-
-import com.android.internal.telephony.TelephonyEvent;
-
-import android.os.Bundle;
-
-/**
- * Interface used to subscribe for events from Telephony debug service.
- *
- * {@hide}
- */
-oneway interface ITelephonyDebugSubscriber {
-
- /**
- * Called when Telephony debug service has events.
- */
- void onEvents(in TelephonyEvent[] events);
-}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyEvent.aidl b/telephony/java/com/android/internal/telephony/TelephonyEvent.aidl
deleted file mode 100644
index 1e74b31..0000000
--- a/telephony/java/com/android/internal/telephony/TelephonyEvent.aidl
+++ /dev/null
@@ -1,19 +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 com.android.internal.telephony;
-
-parcelable TelephonyEvent;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyEvent.java b/telephony/java/com/android/internal/telephony/TelephonyEvent.java
deleted file mode 100644
index 26d466d..0000000
--- a/telephony/java/com/android/internal/telephony/TelephonyEvent.java
+++ /dev/null
@@ -1,84 +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 com.android.internal.telephony;
-
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * A parcelable used in ITelephonyDebugSubscriber.aidl
- */
-public class TelephonyEvent implements Parcelable {
-
- final public long timestamp;
- final public int phoneId;
- final public int tag;
- final public int param1;
- final public int param2;
- final public Bundle data;
-
- public TelephonyEvent(long timestamp, int phoneId, int tag,
- int param1, int param2, Bundle data) {
- this.timestamp = timestamp;
- this.phoneId = phoneId;
- this.tag = tag;
- this.param1 = param1;
- this.param2 = param2;
- this.data = data;
- }
-
- /** Implement the Parcelable interface */
- public static final Parcelable.Creator<TelephonyEvent> CREATOR
- = new Parcelable.Creator<TelephonyEvent> (){
- public TelephonyEvent createFromParcel(Parcel source) {
- final long timestamp = source.readLong();
- final int phoneId = source.readInt();
- final int tag = source.readInt();
- final int param1 = source.readInt();
- final int param2 = source.readInt();
- final Bundle data = source.readBundle();
- return new TelephonyEvent(timestamp, phoneId, tag, param1, param2, data);
- }
-
- public TelephonyEvent[] newArray(int size) {
- return new TelephonyEvent[size];
- }
- };
-
- /** Implement the Parcelable interface */
- @Override
- public int describeContents() {
- return 0;
- }
-
- /** Implement the Parcelable interface */
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeLong(timestamp);
- dest.writeInt(phoneId);
- dest.writeInt(tag);
- dest.writeInt(param1);
- dest.writeInt(param2);
- dest.writeBundle(data);
- }
-
- public String toString() {
- return String.format("%d,%d,%d,%d,%d,%s",
- timestamp, phoneId, tag, param1, param2, data);
- }
-}
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
index 005a483..c1f0038 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
@@ -37,6 +37,8 @@
final int parentLeft, parentTop;
final Matrix matrix;
final String className;
+ final float textSize;
+ final int textColor;
final CharSequence text;
final int scrollY;
final int[] lineCharOffsets;
@@ -50,6 +52,8 @@
this.parentTop = parentTop;
this.matrix = new Matrix(matrix);
this.className = node.getClassName();
+ this.textSize = node.getTextSize();
+ this.textColor = node.getTextColor();
this.text = node.getText() != null ? node.getText() : node.getContentDescription();
this.scrollY = node.getScrollY();
this.lineCharOffsets = node.getTextLineCharOffsets();
@@ -113,7 +117,9 @@
TextEntry te = mTextRects.get(i);
Log.d(TAG, "View " + te.className + " " + te.bounds.toShortString()
+ " in " + te.parentLeft + "," + te.parentTop
- + " matrix=" + te.matrix.toShortString() + ": "
+ + " matrix=" + te.matrix.toShortString()
+ + " size=" + te.textSize + " color=#" + Integer.toHexString(te.textColor)
+ + ": "
+ te.text);
if (te.lineCharOffsets != null && te.lineBaselines != null) {
final int num = te.lineCharOffsets.length < te.lineBaselines.length
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index fb2bdd4..b8ef150 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -1636,6 +1636,9 @@
if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)) {
keyMgmt = KeyMgmt.strings[KeyMgmt.WPA_EAP];
}
+ if (allowedKeyManagement.get(KeyMgmt.OSEN)) {
+ keyMgmt = KeyMgmt.strings[KeyMgmt.OSEN];
+ }
if (allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
keyMgmt += KeyMgmt.strings[KeyMgmt.IEEE8021X];
}
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 394934f..b614a86 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -437,6 +437,7 @@
switch (eapMethod) {
/** Valid methods */
case Eap.TLS:
+ case Eap.UNAUTH_TLS:
setPhase2Method(Phase2.NONE);
/* fall through */
case Eap.PEAP:
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index f8c1ea3..1a8197c 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -687,7 +687,7 @@
Bundle scanParams = new Bundle();
scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource);
- sAsyncChannel.sendMessage(CMD_START_BACKGROUND_SCAN, 0, key, scanParams);
+ mAsyncChannel.sendMessage(CMD_START_BACKGROUND_SCAN, 0, key, scanParams);
}
/**
@@ -700,7 +700,7 @@
int key = removeListener(listener);
if (key == INVALID_KEY) return;
validateChannel();
- sAsyncChannel.sendMessage(CMD_STOP_BACKGROUND_SCAN, 0, key);
+ mAsyncChannel.sendMessage(CMD_STOP_BACKGROUND_SCAN, 0, key);
}
/**
* reports currently available scan results on appropriate listeners
@@ -708,7 +708,7 @@
*/
public boolean getScanResults() {
validateChannel();
- Message reply = sAsyncChannel.sendMessageSynchronously(CMD_GET_SCAN_RESULTS, 0);
+ Message reply = mAsyncChannel.sendMessageSynchronously(CMD_GET_SCAN_RESULTS, 0);
return reply.what == CMD_OP_SUCCEEDED;
}
@@ -741,7 +741,7 @@
Bundle scanParams = new Bundle();
scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource);
- sAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, scanParams);
+ mAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, scanParams);
}
/**
@@ -754,7 +754,7 @@
int key = removeListener(listener);
if (key == INVALID_KEY) return;
validateChannel();
- sAsyncChannel.sendMessage(CMD_STOP_SINGLE_SCAN, 0, key);
+ mAsyncChannel.sendMessage(CMD_STOP_SINGLE_SCAN, 0, key);
}
private void startPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings, int key) {
@@ -764,7 +764,7 @@
scanSettings.isPnoScan = true;
pnoParams.putParcelable(PNO_PARAMS_SCAN_SETTINGS_KEY, scanSettings);
pnoParams.putParcelable(PNO_PARAMS_PNO_SETTINGS_KEY, pnoSettings);
- sAsyncChannel.sendMessage(CMD_START_PNO_SCAN, 0, key, pnoParams);
+ mAsyncChannel.sendMessage(CMD_START_PNO_SCAN, 0, key, pnoParams);
}
/**
* Start wifi connected PNO scan
@@ -820,7 +820,7 @@
int key = removeListener(listener);
if (key == INVALID_KEY) return;
validateChannel();
- sAsyncChannel.sendMessage(CMD_STOP_PNO_SCAN, 0, key);
+ mAsyncChannel.sendMessage(CMD_STOP_PNO_SCAN, 0, key);
}
/** specifies information about an access point of interest */
@@ -956,7 +956,7 @@
int key = addListener(listener);
if (key == INVALID_KEY) return;
validateChannel();
- sAsyncChannel.sendMessage(CMD_START_TRACKING_CHANGE, 0, key);
+ mAsyncChannel.sendMessage(CMD_START_TRACKING_CHANGE, 0, key);
}
/**
@@ -968,14 +968,14 @@
int key = removeListener(listener);
if (key == INVALID_KEY) return;
validateChannel();
- sAsyncChannel.sendMessage(CMD_STOP_TRACKING_CHANGE, 0, key);
+ mAsyncChannel.sendMessage(CMD_STOP_TRACKING_CHANGE, 0, key);
}
/** @hide */
@SystemApi
public void configureWifiChange(WifiChangeSettings settings) {
validateChannel();
- sAsyncChannel.sendMessage(CMD_CONFIGURE_WIFI_CHANGE, 0, 0, settings);
+ mAsyncChannel.sendMessage(CMD_CONFIGURE_WIFI_CHANGE, 0, 0, settings);
}
/** interface to receive hotlist events on; use this on {@link #setHotlist} */
@@ -1060,7 +1060,7 @@
HotlistSettings settings = new HotlistSettings();
settings.bssidInfos = bssidInfos;
settings.apLostThreshold = apLostThreshold;
- sAsyncChannel.sendMessage(CMD_SET_HOTLIST, 0, key, settings);
+ mAsyncChannel.sendMessage(CMD_SET_HOTLIST, 0, key, settings);
}
/**
@@ -1072,7 +1072,7 @@
int key = removeListener(listener);
if (key == INVALID_KEY) return;
validateChannel();
- sAsyncChannel.sendMessage(CMD_RESET_HOTLIST, 0, key);
+ mAsyncChannel.sendMessage(CMD_RESET_HOTLIST, 0, key);
}
@@ -1137,17 +1137,14 @@
private IWifiScanner mService;
private static final int INVALID_KEY = 0;
- private static int sListenerKey = 1;
+ private int mListenerKey = 1;
- private static final SparseArray sListenerMap = new SparseArray();
- private static final Object sListenerMapLock = new Object();
+ private final SparseArray mListenerMap = new SparseArray();
+ private final Object mListenerMapLock = new Object();
- private static AsyncChannel sAsyncChannel;
- private static CountDownLatch sConnected;
-
- private static final Object sThreadRefLock = new Object();
- private static int sThreadRefCount;
- private static Handler sInternalHandler;
+ private AsyncChannel mAsyncChannel;
+ private final CountDownLatch mConnected;
+ private final Handler mInternalHandler;
/**
* Create a new WifiScanner instance.
@@ -1156,10 +1153,11 @@
* the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
* @param context the application context
* @param service the Binder interface
+ * @param looper the Looper used to deliver callbacks
* @hide
*/
- public WifiScanner(Context context, IWifiScanner service) {
- this(context, service, null, true);
+ public WifiScanner(Context context, IWifiScanner service, Looper looper) {
+ this(context, service, looper, true);
}
/**
@@ -1167,8 +1165,7 @@
*
* @param context The application context.
* @param service The IWifiScanner Binder interface
- * @param looper Looper for running WifiScanner operations. If null, a handler thread will be
- * created for running WifiScanner operations.
+ * @param looper the Looper used to deliver callbacks
* @param waitForConnection If true, this will not return until a connection to Wifi Scanner
* service is established.
* @hide
@@ -1178,50 +1175,34 @@
boolean waitForConnection) {
mContext = context;
mService = service;
- init(looper, waitForConnection);
- }
- private void init(Looper looper, boolean waitForConnection) {
- synchronized (sThreadRefLock) {
- if (++sThreadRefCount == 1) {
- Messenger messenger = null;
- try {
- messenger = mService.getMessenger();
- } catch (RemoteException e) {
- /* do nothing */
- } catch (SecurityException e) {
- /* do nothing */
- }
+ Messenger messenger = null;
+ try {
+ messenger = mService.getMessenger();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
- if (messenger == null) {
- sAsyncChannel = null;
- return;
- }
+ if (messenger == null) {
+ throw new IllegalStateException("getMessenger() returned null! This is invalid.");
+ }
- sAsyncChannel = new AsyncChannel();
- sConnected = new CountDownLatch(1);
+ mAsyncChannel = new AsyncChannel();
+ mConnected = new CountDownLatch(1);
- if (looper == null) {
- HandlerThread thread = new HandlerThread("WifiScanner");
- thread.start();
- sInternalHandler = new ServiceHandler(thread.getLooper());
- } else {
- sInternalHandler = new ServiceHandler(looper);
- }
- sAsyncChannel.connect(mContext, sInternalHandler, messenger);
- if (waitForConnection) {
- try {
- sConnected.await();
- } catch (InterruptedException e) {
- Log.e(TAG, "interrupted wait at init");
- }
- }
+ mInternalHandler = new ServiceHandler(looper);
+ mAsyncChannel.connect(mContext, mInternalHandler, messenger);
+ if (waitForConnection) {
+ try {
+ mConnected.await();
+ } catch (InterruptedException e) {
+ Log.e(TAG, "interrupted wait at init");
}
}
}
private void validateChannel() {
- if (sAsyncChannel == null) throw new IllegalStateException(
+ if (mAsyncChannel == null) throw new IllegalStateException(
"No permission to access and change wifi or a bad initialization");
}
@@ -1229,7 +1210,7 @@
// send an error message to internal handler; Otherwise add the listener to the listener map and
// return the key of the listener.
private int addListener(ActionListener listener) {
- synchronized (sListenerMap) {
+ synchronized (mListenerMapLock) {
boolean keyExists = (getListenerKey(listener) != INVALID_KEY);
// Note we need to put the listener into listener map even if it's a duplicate as the
// internal handler will need the key to find the listener. In case of duplicates,
@@ -1239,7 +1220,7 @@
if (DBG) Log.d(TAG, "listener key already exists");
OperationResult operationResult = new OperationResult(REASON_DUPLICATE_REQEUST,
"Outstanding request with same key not stopped yet");
- Message message = Message.obtain(sInternalHandler, CMD_OP_FAILED, 0, key,
+ Message message = Message.obtain(mInternalHandler, CMD_OP_FAILED, 0, key,
operationResult);
message.sendToTarget();
return INVALID_KEY;
@@ -1249,55 +1230,55 @@
}
}
- private static int putListener(Object listener) {
+ private int putListener(Object listener) {
if (listener == null) return INVALID_KEY;
int key;
- synchronized (sListenerMapLock) {
+ synchronized (mListenerMapLock) {
do {
- key = sListenerKey++;
+ key = mListenerKey++;
} while (key == INVALID_KEY);
- sListenerMap.put(key, listener);
+ mListenerMap.put(key, listener);
}
return key;
}
- private static Object getListener(int key) {
+ private Object getListener(int key) {
if (key == INVALID_KEY) return null;
- synchronized (sListenerMapLock) {
- Object listener = sListenerMap.get(key);
+ synchronized (mListenerMapLock) {
+ Object listener = mListenerMap.get(key);
return listener;
}
}
- private static int getListenerKey(Object listener) {
+ private int getListenerKey(Object listener) {
if (listener == null) return INVALID_KEY;
- synchronized (sListenerMapLock) {
- int index = sListenerMap.indexOfValue(listener);
+ synchronized (mListenerMapLock) {
+ int index = mListenerMap.indexOfValue(listener);
if (index == -1) {
return INVALID_KEY;
} else {
- return sListenerMap.keyAt(index);
+ return mListenerMap.keyAt(index);
}
}
}
- private static Object removeListener(int key) {
+ private Object removeListener(int key) {
if (key == INVALID_KEY) return null;
- synchronized (sListenerMapLock) {
- Object listener = sListenerMap.get(key);
- sListenerMap.remove(key);
+ synchronized (mListenerMapLock) {
+ Object listener = mListenerMap.get(key);
+ mListenerMap.remove(key);
return listener;
}
}
- private static int removeListener(Object listener) {
+ private int removeListener(Object listener) {
int key = getListenerKey(listener);
if (key == INVALID_KEY) {
Log.e(TAG, "listener cannot be found");
return key;
}
- synchronized (sListenerMapLock) {
- sListenerMap.remove(key);
+ synchronized (mListenerMapLock) {
+ mListenerMap.remove(key);
return key;
}
}
@@ -1338,7 +1319,7 @@
};
}
- private static class ServiceHandler extends Handler {
+ private class ServiceHandler extends Handler {
ServiceHandler(Looper looper) {
super(looper);
}
@@ -1347,14 +1328,14 @@
switch (msg.what) {
case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
- sAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
+ mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
} else {
Log.e(TAG, "Failed to set up channel connection");
// This will cause all further async API calls on the WifiManager
// to fail and throw an exception
- sAsyncChannel = null;
+ mAsyncChannel = null;
}
- sConnected.countDown();
+ mConnected.countDown();
return;
case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
return;
@@ -1362,7 +1343,7 @@
Log.e(TAG, "Channel connection lost");
// This will cause all further async API calls on the WifiManager
// to fail and throw an exception
- sAsyncChannel = null;
+ mAsyncChannel = null;
getLooper().quit();
return;
}