Merge "Don't call surface.remove if surface is null." into oc-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index 4f117ee..7584ba8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4214,12 +4214,6 @@
public class Application extends android.content.ContextWrapper implements android.content.ComponentCallbacks2 {
ctor public Application();
- method public android.app.Activity instantiateActivity(java.lang.ClassLoader, java.lang.String, android.content.Intent);
- method public android.app.backup.BackupAgent instantiateBackupAgent(java.lang.ClassLoader, java.lang.String);
- method public android.app.Instrumentation instantiateInstrumentation(java.lang.ClassLoader, java.lang.String);
- method public android.content.ContentProvider instantiateProvider(java.lang.ClassLoader, java.lang.String);
- method public android.content.BroadcastReceiver instantiateReceiver(java.lang.ClassLoader, java.lang.String, android.content.Intent);
- method public android.app.Service instantiateService(java.lang.ClassLoader, java.lang.String, android.content.Intent);
method public void onConfigurationChanged(android.content.res.Configuration);
method public void onCreate();
method public void onLowMemory();
@@ -6140,7 +6134,6 @@
}
public class WallpaperManager {
- method public void addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener);
method public void addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener, android.os.Handler);
method public void clear() throws java.io.IOException;
method public void clear(int) throws java.io.IOException;
@@ -26034,8 +26027,8 @@
method public boolean protect(java.net.Socket);
method public boolean protect(java.net.DatagramSocket);
method public boolean setUnderlyingNetworks(android.net.Network[]);
- field public static final java.lang.String METADATA_SUPPORTS_ALWAYS_ON = "android.net.VpnService.SUPPORTS_ALWAYS_ON";
field public static final java.lang.String SERVICE_INTERFACE = "android.net.VpnService";
+ field public static final java.lang.String SERVICE_META_DATA_SUPPORTS_ALWAYS_ON = "android.net.VpnService.SUPPORTS_ALWAYS_ON";
}
public class VpnService.Builder {
@@ -38884,7 +38877,7 @@
public static final class Call.RttCall {
method public int getRttAudioMode();
- method public java.lang.String read() throws java.io.IOException;
+ method public java.lang.String read();
method public java.lang.String readImmediately() throws java.io.IOException;
method public void setRttMode(int);
method public void write(java.lang.String) throws java.io.IOException;
@@ -39601,6 +39594,7 @@
field public static final java.lang.String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string";
field public static final java.lang.String KEY_DIAL_STRING_REPLACE_STRING_ARRAY = "dial_string_replace_string_array";
field public static final java.lang.String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
+ field public static final java.lang.String KEY_DISPLAY_HD_AUDIO_PROPERTY_BOOL = "display_hd_audio_property_bool";
field public static final java.lang.String KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL = "drop_video_call_when_answering_audio_call_bool";
field public static final java.lang.String KEY_DTMF_TYPE_ENABLED_BOOL = "dtmf_type_enabled_bool";
field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
@@ -45234,15 +45228,11 @@
public class Surface implements android.os.Parcelable {
ctor public Surface(android.graphics.SurfaceTexture);
method public int describeContents();
- method public boolean isAutoRefreshEnabled();
- method public boolean isSharedBufferModeEnabled();
method public boolean isValid();
method public android.graphics.Canvas lockCanvas(android.graphics.Rect) throws java.lang.IllegalArgumentException, android.view.Surface.OutOfResourcesException;
method public android.graphics.Canvas lockHardwareCanvas();
method public void readFromParcel(android.os.Parcel);
method public void release();
- method public void setAutoRefreshEnabled(boolean);
- method public void setSharedBufferModeEnabled(boolean);
method public deprecated void unlockCanvas(android.graphics.Canvas);
method public void unlockCanvasAndPost(android.graphics.Canvas);
method public void writeToParcel(android.os.Parcel, int);
diff --git a/api/system-current.txt b/api/system-current.txt
index e8c56f0..9963268 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4378,12 +4378,6 @@
public class Application extends android.content.ContextWrapper implements android.content.ComponentCallbacks2 {
ctor public Application();
- method public android.app.Activity instantiateActivity(java.lang.ClassLoader, java.lang.String, android.content.Intent);
- method public android.app.backup.BackupAgent instantiateBackupAgent(java.lang.ClassLoader, java.lang.String);
- method public android.app.Instrumentation instantiateInstrumentation(java.lang.ClassLoader, java.lang.String);
- method public android.content.ContentProvider instantiateProvider(java.lang.ClassLoader, java.lang.String);
- method public android.content.BroadcastReceiver instantiateReceiver(java.lang.ClassLoader, java.lang.String, android.content.Intent);
- method public android.app.Service instantiateService(java.lang.ClassLoader, java.lang.String, android.content.Intent);
method public void onConfigurationChanged(android.content.res.Configuration);
method public void onCreate();
method public void onLowMemory();
@@ -6350,7 +6344,6 @@
}
public class WallpaperManager {
- method public void addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener);
method public void addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener, android.os.Handler);
method public void clear() throws java.io.IOException;
method public void clear(int) throws java.io.IOException;
@@ -28332,8 +28325,8 @@
method public boolean protect(java.net.Socket);
method public boolean protect(java.net.DatagramSocket);
method public boolean setUnderlyingNetworks(android.net.Network[]);
- field public static final java.lang.String METADATA_SUPPORTS_ALWAYS_ON = "android.net.VpnService.SUPPORTS_ALWAYS_ON";
field public static final java.lang.String SERVICE_INTERFACE = "android.net.VpnService";
+ field public static final java.lang.String SERVICE_META_DATA_SUPPORTS_ALWAYS_ON = "android.net.VpnService.SUPPORTS_ALWAYS_ON";
}
public class VpnService.Builder {
@@ -42129,7 +42122,7 @@
public static final class Call.RttCall {
method public int getRttAudioMode();
- method public java.lang.String read() throws java.io.IOException;
+ method public java.lang.String read();
method public java.lang.String readImmediately() throws java.io.IOException;
method public void setRttMode(int);
method public void write(java.lang.String) throws java.io.IOException;
@@ -43040,6 +43033,7 @@
field public static final java.lang.String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string";
field public static final java.lang.String KEY_DIAL_STRING_REPLACE_STRING_ARRAY = "dial_string_replace_string_array";
field public static final java.lang.String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
+ field public static final java.lang.String KEY_DISPLAY_HD_AUDIO_PROPERTY_BOOL = "display_hd_audio_property_bool";
field public static final java.lang.String KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL = "drop_video_call_when_answering_audio_call_bool";
field public static final java.lang.String KEY_DTMF_TYPE_ENABLED_BOOL = "dtmf_type_enabled_bool";
field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
@@ -48819,15 +48813,11 @@
public class Surface implements android.os.Parcelable {
ctor public Surface(android.graphics.SurfaceTexture);
method public int describeContents();
- method public boolean isAutoRefreshEnabled();
- method public boolean isSharedBufferModeEnabled();
method public boolean isValid();
method public android.graphics.Canvas lockCanvas(android.graphics.Rect) throws java.lang.IllegalArgumentException, android.view.Surface.OutOfResourcesException;
method public android.graphics.Canvas lockHardwareCanvas();
method public void readFromParcel(android.os.Parcel);
method public void release();
- method public void setAutoRefreshEnabled(boolean);
- method public void setSharedBufferModeEnabled(boolean);
method public deprecated void unlockCanvas(android.graphics.Canvas);
method public void unlockCanvasAndPost(android.graphics.Canvas);
method public void writeToParcel(android.os.Parcel, int);
diff --git a/api/test-current.txt b/api/test-current.txt
index 56308b0..1258554 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -4227,12 +4227,6 @@
public class Application extends android.content.ContextWrapper implements android.content.ComponentCallbacks2 {
ctor public Application();
- method public android.app.Activity instantiateActivity(java.lang.ClassLoader, java.lang.String, android.content.Intent);
- method public android.app.backup.BackupAgent instantiateBackupAgent(java.lang.ClassLoader, java.lang.String);
- method public android.app.Instrumentation instantiateInstrumentation(java.lang.ClassLoader, java.lang.String);
- method public android.content.ContentProvider instantiateProvider(java.lang.ClassLoader, java.lang.String);
- method public android.content.BroadcastReceiver instantiateReceiver(java.lang.ClassLoader, java.lang.String, android.content.Intent);
- method public android.app.Service instantiateService(java.lang.ClassLoader, java.lang.String, android.content.Intent);
method public void onConfigurationChanged(android.content.res.Configuration);
method public void onCreate();
method public void onLowMemory();
@@ -6161,7 +6155,6 @@
}
public class WallpaperManager {
- method public void addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener);
method public void addOnColorsChangedListener(android.app.WallpaperManager.OnColorsChangedListener, android.os.Handler);
method public void clear() throws java.io.IOException;
method public void clear(int) throws java.io.IOException;
@@ -26178,8 +26171,8 @@
method public boolean protect(java.net.Socket);
method public boolean protect(java.net.DatagramSocket);
method public boolean setUnderlyingNetworks(android.net.Network[]);
- field public static final java.lang.String METADATA_SUPPORTS_ALWAYS_ON = "android.net.VpnService.SUPPORTS_ALWAYS_ON";
field public static final java.lang.String SERVICE_INTERFACE = "android.net.VpnService";
+ field public static final java.lang.String SERVICE_META_DATA_SUPPORTS_ALWAYS_ON = "android.net.VpnService.SUPPORTS_ALWAYS_ON";
}
public class VpnService.Builder {
@@ -39127,7 +39120,7 @@
public static final class Call.RttCall {
method public int getRttAudioMode();
- method public java.lang.String read() throws java.io.IOException;
+ method public java.lang.String read();
method public java.lang.String readImmediately() throws java.io.IOException;
method public void setRttMode(int);
method public void write(java.lang.String) throws java.io.IOException;
@@ -39860,6 +39853,7 @@
field public static final java.lang.String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string";
field public static final java.lang.String KEY_DIAL_STRING_REPLACE_STRING_ARRAY = "dial_string_replace_string_array";
field public static final java.lang.String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool";
+ field public static final java.lang.String KEY_DISPLAY_HD_AUDIO_PROPERTY_BOOL = "display_hd_audio_property_bool";
field public static final java.lang.String KEY_DROP_VIDEO_CALL_WHEN_ANSWERING_AUDIO_CALL_BOOL = "drop_video_call_when_answering_audio_call_bool";
field public static final java.lang.String KEY_DTMF_TYPE_ENABLED_BOOL = "dtmf_type_enabled_bool";
field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
@@ -45672,15 +45666,11 @@
public class Surface implements android.os.Parcelable {
ctor public Surface(android.graphics.SurfaceTexture);
method public int describeContents();
- method public boolean isAutoRefreshEnabled();
- method public boolean isSharedBufferModeEnabled();
method public boolean isValid();
method public android.graphics.Canvas lockCanvas(android.graphics.Rect) throws java.lang.IllegalArgumentException, android.view.Surface.OutOfResourcesException;
method public android.graphics.Canvas lockHardwareCanvas();
method public void readFromParcel(android.os.Parcel);
method public void release();
- method public void setAutoRefreshEnabled(boolean);
- method public void setSharedBufferModeEnabled(boolean);
method public deprecated void unlockCanvas(android.graphics.Canvas);
method public void unlockCanvasAndPost(android.graphics.Canvas);
method public void writeToParcel(android.os.Parcel, int);
diff --git a/config/generate-preloaded-classes.sh b/config/generate-preloaded-classes.sh
index d55190b..e36e148 100755
--- a/config/generate-preloaded-classes.sh
+++ b/config/generate-preloaded-classes.sh
@@ -17,6 +17,10 @@
echo "Usage $0 <input classes file> <blacklist file> [extra classes files]"
exit 1
fi
+
+# Write file headers first
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+cat "$DIR/copyright-header"
echo "# Preloaded-classes filter file for phones.
#
# Classes in this file will be allocated into the boot image, and forcibly initialized in
@@ -25,9 +29,11 @@
#
# This file has been derived for mainline phone (and tablet) usage.
#"
+
input=$1
blacklist=$2
shift 2
extra_classes_files=("$@")
-sort "$input" "${extra_classes_files[@]}" | uniq | grep -f "$blacklist" -v -F -x
+# Disable locale to enable lexicographical sorting
+LC_ALL=C sort "$input" "${extra_classes_files[@]}" | uniq | grep -f "$blacklist" -v -F -x
diff --git a/config/preloaded-classes b/config/preloaded-classes
index b6be0ee..1c842c7 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -13,8 +13,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-#
-#
# Preloaded-classes filter file for phones.
#
# Classes in this file will be allocated into the boot image, and forcibly initialized in
@@ -1454,6 +1452,7 @@
android.icu.impl.UResource$Table
android.icu.impl.UResource$Value
android.icu.impl.Utility
+android.icu.impl.coll.CollationRoot
android.icu.impl.locale.AsciiUtil
android.icu.impl.locale.BaseLocale
android.icu.impl.locale.BaseLocale$Cache
@@ -2276,7 +2275,6 @@
android.util.Base64$Coder
android.util.Base64$Decoder
android.util.Base64$Encoder
-android.util.TimingsTraceLog
android.util.ContainerHelpers
android.util.DisplayMetrics
android.util.EventLog
@@ -2328,6 +2326,7 @@
android.util.StateSet
android.util.SuperNotCalledException
android.util.TimeUtils
+android.util.TimingsTraceLog
android.util.TypedValue
android.util.Xml
android.util.jar.StrictJarFile
diff --git a/config/preloaded-classes-extra b/config/preloaded-classes-extra
new file mode 100644
index 0000000..1934cbc
--- /dev/null
+++ b/config/preloaded-classes-extra
@@ -0,0 +1 @@
+android.icu.impl.coll.CollationRoot
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 2166c3c..b2fd169 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1006,11 +1006,6 @@
Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.fragments : null);
- } else {
- AutofillManager afm = getAutofillManager();
- if (afm != null) {
- afm.dismissUi();
- }
}
mFragments.dispatchCreate();
getApplication().dispatchActivityCreated(this, savedInstanceState);
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index e5fe240..68fb7bc 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -30,8 +30,6 @@
import com.android.internal.app.IVoiceInteractor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
import java.util.List;
/**
@@ -90,11 +88,12 @@
String processName, String abiOverride, int uid, Runnable crashHandler);
/**
- * Acquires a sleep token with the specified tag.
+ * Acquires a sleep token for the specified display with the specified tag.
*
* @param tag A string identifying the purpose of the token (eg. "Dream").
+ * @param displayId The display to apply the sleep token to.
*/
- public abstract SleepToken acquireSleepToken(@NonNull String tag);
+ public abstract SleepToken acquireSleepToken(@NonNull String tag, int displayId);
/**
* Sleep tokens cause the activity manager to put the top activity to sleep.
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 43693e1..2e4ce18 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2666,14 +2666,8 @@
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
- if (appContext.getApplicationContext() instanceof Application) {
- activity = ((Application) appContext.getApplicationContext())
- .instantiateActivity(cl, component.getClassName(), r.intent);
- }
- if (activity == null) {
- activity = mInstrumentation.newActivity(
- cl, component.getClassName(), r.intent);
- }
+ activity = mInstrumentation.newActivity(
+ cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
@@ -3169,8 +3163,7 @@
data.intent.setExtrasClassLoader(cl);
data.intent.prepareToEnterProcess();
data.setExtrasClassLoader(cl);
- receiver = instantiate(cl, component, data.intent, app,
- Application::instantiateReceiver);
+ receiver = (BroadcastReceiver)cl.loadClass(component).newInstance();
} catch (Exception e) {
if (DEBUG_BROADCAST) Slog.i(TAG,
"Finishing failed broadcast to " + data.intent.getComponent());
@@ -3258,13 +3251,12 @@
} else {
try {
if (DEBUG_BACKUP) Slog.v(TAG, "Initializing agent class " + classname);
- ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
java.lang.ClassLoader cl = packageInfo.getClassLoader();
- agent = instantiate(cl, classname, context,
- Application::instantiateBackupAgent);
+ agent = (BackupAgent) cl.loadClass(classname).newInstance();
// set up the agent's context
+ ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(agent);
agent.attach(context);
@@ -3324,12 +3316,9 @@
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
- Application app = null;
try {
- app = packageInfo.makeApplication(false, mInstrumentation);
java.lang.ClassLoader cl = packageInfo.getClassLoader();
- service = instantiate(cl, data.info.name, data.intent, app,
- Application::instantiateService);
+ service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
@@ -3344,6 +3333,7 @@
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
context.setOuterContext(service);
+ Application app = packageInfo.makeApplication(false, mInstrumentation);
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
service.onCreate();
@@ -5682,8 +5672,8 @@
try {
final ClassLoader cl = instrContext.getClassLoader();
- mInstrumentation = instantiate(cl, data.instrumentationName.getClassName(),
- instrContext, Application::instantiateInstrumentation);
+ mInstrumentation = (Instrumentation)
+ cl.loadClass(data.instrumentationName.getClassName()).newInstance();
} catch (Exception e) {
throw new RuntimeException(
"Unable to instantiate instrumentation "
@@ -6234,8 +6224,8 @@
try {
final java.lang.ClassLoader cl = c.getClassLoader();
- localProvider = instantiate(cl, info.name, context,
- Application::instantiateProvider);
+ localProvider = (ContentProvider)cl.
+ loadClass(info.name).newInstance();
provider = localProvider.getIContentProvider();
if (provider == null) {
Slog.e(TAG, "Failed to instantiate class " +
@@ -6434,49 +6424,6 @@
}
}
- private <T> T instantiate(ClassLoader cl, String className, Context c,
- Instantiator<T> instantiator)
- throws ClassNotFoundException, IllegalAccessException, InstantiationException {
- Application app = getApp(c);
- if (app != null) {
- T a = instantiator.instantiate(app, cl, className);
- if (a != null) return a;
- }
- return (T) cl.loadClass(className).newInstance();
- }
-
- private <T> T instantiate(ClassLoader cl, String className, Intent intent, Context c,
- IntentInstantiator<T> instantiator)
- throws ClassNotFoundException, IllegalAccessException, InstantiationException {
- Application app = getApp(c);
- if (app != null) {
- T a = instantiator.instantiate(app, cl, className, intent);
- if (a != null) return a;
- }
- return (T) cl.loadClass(className).newInstance();
- }
-
- private Application getApp(Context c) {
- // We need this shortcut to avoid actually calling getApplicationContext() on an Application
- // because the Application may not return itself for getApplicationContext() because the
- // API doesn't enforce it.
- if (c instanceof Application) return (Application) c;
- if (c.getApplicationContext() instanceof Application) {
- return (Application) c.getApplicationContext();
- }
- return null;
- }
-
- private interface Instantiator<T> {
- T instantiate(Application app, ClassLoader cl, String className)
- throws ClassNotFoundException, IllegalAccessException, InstantiationException;
- }
-
- private interface IntentInstantiator<T> {
- T instantiate(Application app, ClassLoader cl, String className, Intent intent)
- throws ClassNotFoundException, IllegalAccessException, InstantiationException;
- }
-
private static class EventLoggingReporter implements EventLogger.Reporter {
@Override
public void report (int code, Object... list) {
diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java
index cc23ec9..156df36 100644
--- a/core/java/android/app/Application.java
+++ b/core/java/android/app/Application.java
@@ -16,20 +16,17 @@
package android.app;
+import java.util.ArrayList;
+
import android.annotation.CallSuper;
-import android.app.backup.BackupAgent;
-import android.content.BroadcastReceiver;
import android.content.ComponentCallbacks;
import android.content.ComponentCallbacks2;
-import android.content.ContentProvider;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
-import java.util.ArrayList;
-
/**
* Base class for maintaining global application state. You can provide your own
* implementation by creating a subclass and specifying the fully-qualified name
@@ -292,73 +289,4 @@
}
}
}
-
- /**
- * Allows application to override the creation of activities. This can be used to
- * perform things such as dependency injection or class loader changes to these
- * classes. Return null to use the default creation flow.
- * @param cl The default classloader to use for instantiation.
- * @param className The class to be instantiated.
- * @param intent Intent creating the class.
- */
- public Activity instantiateActivity(ClassLoader cl, String className, Intent intent) {
- return null;
- }
-
- /**
- * Allows application to override the creation of receivers. This can be used to
- * perform things such as dependency injection or class loader changes to these
- * classes. Return null to use the default creation flow.
- * @param cl The default classloader to use for instantiation.
- * @param className The class to be instantiated.
- * @param intent Intent creating the class.
- */
- public BroadcastReceiver instantiateReceiver(ClassLoader cl, String className, Intent intent) {
- return null;
- }
-
- /**
- * Allows application to override the creation of services. This can be used to
- * perform things such as dependency injection or class loader changes to these
- * classes. Return null to use the default creation flow.
- * @param cl The default classloader to use for instantiation.
- * @param className The class to be instantiated.
- * @param intent Intent creating the class.
- */
- public Service instantiateService(ClassLoader cl, String className, Intent intent) {
- return null;
- }
-
- /**
- * Allows application to override the creation of providers. This can be used to
- * perform things such as dependency injection or class loader changes to these
- * classes. Return null to use the default creation flow.
- * @param cl The default classloader to use for instantiation.
- * @param className The class to be instantiated.
- */
- public ContentProvider instantiateProvider(ClassLoader cl, String className) {
- return null;
- }
-
- /**
- * Allows application to override the creation of backup agents. This can be used to
- * perform things such as dependency injection or class loader changes to these
- * classes. Return null to use the default creation flow.
- * @param cl The default classloader to use for instantiation.
- * @param className The class to be instantiated.
- */
- public BackupAgent instantiateBackupAgent(ClassLoader cl, String className) {
- return null;
- }
-
- /**
- * Allows application to override the creation of instrumentation. This can be used to
- * perform things such as dependency injection or class loader changes to these
- * classes. Return null to use the default creation flow.
- * @param cl The default classloader to use for instantiation.
- * @param className The class to be instantiated.
- */
- public Instrumentation instantiateInstrumentation(ClassLoader cl, String className) {
- return null;
- }
}
\ No newline at end of file
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index a218274..586f13f 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1164,7 +1164,8 @@
* Constant for {@link Builder#setGroupAlertBehavior(int)}, meaning that all children
* notification in a group should be silenced (no sound or vibration) even if they are posted
* to a {@link NotificationChannel} that has sound and/or vibration. Use this constant to
- * mute this notification if this notification is a group child.
+ * mute this notification if this notification is a group child. This must be applied to all
+ * children notifications you want to mute.
*
* <p> For example, you might want to use this constant if you post a number of children
* notifications at once (say, after a periodic sync), and only need to notify the user
@@ -1179,7 +1180,8 @@
* to mute this notification if this notification is a group summary.
*
* <p>For example, you might want to use this constant if only the children notifications
- * in your group have content and the summary is only used to visually group notifications.
+ * in your group have content and the summary is only used to visually group notifications
+ * rather than to alert the user that new information is available.
*/
public static final int GROUP_ALERT_CHILDREN = 2;
@@ -2914,7 +2916,9 @@
* Sets the group alert behavior for this notification. Use this method to mute this
* notification if alerts for this notification's group should be handled by a different
* notification. This is only applicable for notifications that belong to a
- * {@link #setGroup(String) group}.
+ * {@link #setGroup(String) group}. This must be called on all notifications you want to
+ * mute. For example, if you want only the summary of your group to make noise, all
+ * children in the group should have the group alert behavior {@link #GROUP_ALERT_SUMMARY}.
*
* <p> The default value is {@link #GROUP_ALERT_ALL}.</p>
*/
@@ -5182,17 +5186,22 @@
if (extras.getBoolean(EXTRA_REDUCED_IMAGES)) {
return;
}
+ boolean isLowRam = ActivityManager.isLowRamDeviceStatic();
if (mLargeIcon != null || largeIcon != null) {
Resources resources = context.getResources();
Class<? extends Style> style = getNotificationStyle();
- int maxWidth = resources.getDimensionPixelSize(R.dimen.notification_right_icon_size);
+ int maxWidth = resources.getDimensionPixelSize(isLowRam
+ ? R.dimen.notification_right_icon_size_low_ram
+ : R.dimen.notification_right_icon_size);
int maxHeight = maxWidth;
if (MediaStyle.class.equals(style)
|| DecoratedMediaCustomViewStyle.class.equals(style)) {
- maxHeight = resources.getDimensionPixelSize(
- R.dimen.notification_media_image_max_height);
- maxWidth = resources.getDimensionPixelSize(
- R.dimen.notification_media_image_max_width);
+ maxHeight = resources.getDimensionPixelSize(isLowRam
+ ? R.dimen.notification_media_image_max_height_low_ram
+ : R.dimen.notification_media_image_max_height);
+ maxWidth = resources.getDimensionPixelSize(isLowRam
+ ? R.dimen.notification_media_image_max_width_low_ram
+ : R.dimen.notification_media_image_max_width);
}
if (mLargeIcon != null) {
mLargeIcon.scaleDownIfNecessary(maxWidth, maxHeight);
@@ -5201,19 +5210,22 @@
largeIcon = Icon.scaleDownIfNecessary(largeIcon, maxWidth, maxHeight);
}
}
- reduceImageSizesForRemoteView(contentView, context);
- reduceImageSizesForRemoteView(headsUpContentView, context);
- reduceImageSizesForRemoteView(bigContentView, context);
+ reduceImageSizesForRemoteView(contentView, context, isLowRam);
+ reduceImageSizesForRemoteView(headsUpContentView, context, isLowRam);
+ reduceImageSizesForRemoteView(bigContentView, context, isLowRam);
extras.putBoolean(EXTRA_REDUCED_IMAGES, true);
}
- private void reduceImageSizesForRemoteView(RemoteViews remoteView, Context context) {
+ private void reduceImageSizesForRemoteView(RemoteViews remoteView, Context context,
+ boolean isLowRam) {
if (remoteView != null) {
Resources resources = context.getResources();
- int maxWidth = resources.getDimensionPixelSize(
- R.dimen.notification_custom_view_max_image_width);
- int maxHeight = resources.getDimensionPixelSize(
- R.dimen.notification_custom_view_max_image_height);
+ int maxWidth = resources.getDimensionPixelSize(isLowRam
+ ? R.dimen.notification_custom_view_max_image_width_low_ram
+ : R.dimen.notification_custom_view_max_image_width);
+ int maxHeight = resources.getDimensionPixelSize(isLowRam
+ ? R.dimen.notification_custom_view_max_image_height_low_ram
+ : R.dimen.notification_custom_view_max_image_height);
remoteView.reduceImageSizes(maxWidth, maxHeight);
}
}
@@ -5629,16 +5641,20 @@
public void reduceImageSizes(Context context) {
super.reduceImageSizes(context);
Resources resources = context.getResources();
+ boolean isLowRam = ActivityManager.isLowRamDeviceStatic();
if (mPicture != null) {
- int maxPictureWidth = resources.getDimensionPixelSize(
- R.dimen.notification_big_picture_max_height);
- int maxPictureHeight = resources.getDimensionPixelSize(
- R.dimen.notification_big_picture_max_width);
+ int maxPictureWidth = resources.getDimensionPixelSize(isLowRam
+ ? R.dimen.notification_big_picture_max_height_low_ram
+ : R.dimen.notification_big_picture_max_height);
+ int maxPictureHeight = resources.getDimensionPixelSize(isLowRam
+ ? R.dimen.notification_big_picture_max_width_low_ram
+ : R.dimen.notification_big_picture_max_width);
mPicture = Icon.scaleDownIfNecessary(mPicture, maxPictureWidth, maxPictureHeight);
}
if (mBigLargeIcon != null) {
- int rightIconSize = resources.getDimensionPixelSize(
- R.dimen.notification_right_icon_size);
+ int rightIconSize = resources.getDimensionPixelSize(isLowRam
+ ? R.dimen.notification_right_icon_size_low_ram
+ : R.dimen.notification_right_icon_size);
mBigLargeIcon.scaleDownIfNecessary(rightIconSize, rightIconSize);
}
}
diff --git a/core/java/android/app/NotificationChannelGroup.java b/core/java/android/app/NotificationChannelGroup.java
index 7e8f191a..18ad9cf 100644
--- a/core/java/android/app/NotificationChannelGroup.java
+++ b/core/java/android/app/NotificationChannelGroup.java
@@ -15,24 +15,18 @@
*/
package android.app;
-import android.annotation.StringRes;
import android.annotation.SystemApi;
import android.content.Intent;
-import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
-import android.service.notification.NotificationListenerService;
import android.text.TextUtils;
-import android.util.Slog;
import org.json.JSONException;
import org.json.JSONObject;
-import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
/**
@@ -115,10 +109,8 @@
return mName;
}
- /*
+ /**
* Returns the list of channels that belong to this group
- *
- * @hide
*/
public List<NotificationChannel> getChannels() {
return mChannels;
diff --git a/core/java/android/app/WallpaperColors.java b/core/java/android/app/WallpaperColors.java
index 2a8130f..a2864b9 100644
--- a/core/java/android/app/WallpaperColors.java
+++ b/core/java/android/app/WallpaperColors.java
@@ -49,7 +49,7 @@
* eg. A launcher may set its text color to black if this flag is specified.
* @hide
*/
- public static final int HINT_SUPPORTS_DARK_TEXT = 0x1;
+ public static final int HINT_SUPPORTS_DARK_TEXT = 1 << 0;
/**
* Specifies that dark theme is preferred over the current wallpaper for best presentation.
@@ -57,7 +57,13 @@
* eg. A launcher may set its drawer color to black if this flag is specified.
* @hide
*/
- public static final int HINT_SUPPORTS_DARK_THEME = 0x2;
+ public static final int HINT_SUPPORTS_DARK_THEME = 1 << 1;
+
+ /**
+ * Specifies that this object was generated by extracting colors from a bitmap.
+ * @hide
+ */
+ public static final int HINT_FROM_BITMAP = 1 << 2;
// Maximum size that a bitmap can have to keep our calculations sane
private static final int MAX_BITMAP_SIZE = 112;
@@ -180,13 +186,13 @@
}
}
- int hints = calculateHints(bitmap);
+ int hints = calculateDarkHints(bitmap);
if (shouldRecycle) {
bitmap.recycle();
}
- return new WallpaperColors(primary, secondary, tertiary, hints);
+ return new WallpaperColors(primary, secondary, tertiary, HINT_FROM_BITMAP | hints);
}
/**
@@ -348,7 +354,7 @@
* @param source What to read.
* @return Whether image supports dark text or not.
*/
- private static int calculateHints(Bitmap source) {
+ private static int calculateDarkHints(Bitmap source) {
if (source == null) {
return 0;
}
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 16d0214..b9e7397 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -59,6 +59,7 @@
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.service.wallpaper.WallpaperService;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
@@ -855,16 +856,6 @@
/**
* Registers a listener to get notified when the wallpaper colors change.
- * Callback might be called from an arbitrary background thread.
- *
- * @param listener A listener to register
- */
- public void addOnColorsChangedListener(@NonNull OnColorsChangedListener listener) {
- addOnColorsChangedListener(listener, null);
- }
-
- /**
- * Registers a listener to get notified when the wallpaper colors change
* @param listener A listener to register
* @param handler Where to call it from. Will be called from the main thread
* if null.
@@ -907,10 +898,16 @@
}
/**
- * Get the primary colors of a wallpaper
- * @param which wallpaper type. Must be either {@link #FLAG_SYSTEM} or
- * {@link #FLAG_LOCK}
- * @return {@link WallpaperColors} or null if colors are unknown.
+ * Get the primary colors of a wallpaper.
+ *
+ * <p>You can expect null if:
+ * • Colors are still being processed by the system.
+ * • A live wallpaper doesn't implement {@link WallpaperService.Engine#onComputeColors()}.
+ *
+ * @param which Wallpaper type. Must be either {@link #FLAG_SYSTEM} or
+ * {@link #FLAG_LOCK}.
+ * @return Current {@link WallpaperColors} or null if colors are unknown.
+ * @see #addOnColorsChangedListener(OnColorsChangedListener, Handler)
*/
public @Nullable WallpaperColors getWallpaperColors(int which) {
return getWallpaperColors(which, mContext.getUserId());
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 32a64b0..56123a7 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3939,7 +3939,7 @@
* {@link android.Manifest.permission#BIND_VPN_SERVICE};</li>
* <li>target {@link android.os.Build.VERSION_CODES#N API 24} or above; and</li>
* <li><i>not</i> explicitly opt out of the feature through
- * {@link android.net.VpnService#METADATA_SUPPORTS_ALWAYS_ON}.</li>
+ * {@link android.net.VpnService#SERVICE_META_DATA_SUPPORTS_ALWAYS_ON}.</li>
* </ul>
* The call will fail if called with the package name of an unsupported VPN app.
*
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index c0b82b4..61b0eb0 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -36,161 +36,72 @@
import java.util.List;
/**
- * The ShortcutManager manages an app's <em>shortcuts</em>. Shortcuts provide users
- * with quick access to activities other than an app's main activity in the currently-active
- * launcher. For example,
- * an email app may publish the "compose new email" action, which will directly open the
- * compose activity. The {@link ShortcutInfo} class contains information about each of the
- * shortcuts themselves.
+ * The ShortcutManager manages an app's <em>shortcuts</em>. Shortcuts provide users with quick
+ * access to activities other than an app's main activity in the currently-active launcher, provided
+ * that the launcher supports app shortcuts. For example, an email app may publish the "compose new
+ * email" action, which will directly open the compose activity. The {@link ShortcutInfo} class
+ * contains information about each of the shortcuts themselves.
*
- * <h3>Static Shortcuts and Dynamic Shortcuts</h3>
+ * <p>This page discusses the implementation details of the <code>ShortcutManager</code> class. For
+ * guidance on performing operations on app shortcuts within your app, see the
+ * <a href="/guide/topics/ui/shortcuts.html">App Shortcuts</a> feature guide.
*
- * <p>
- * There are several different types of shortcuts:
+ * <h3>Shortcut characteristics</h3>
*
- * <ul>
- * <li><p>Static shortcuts are declared in a resource XML file, which is referenced in the publisher
- * app's <code>AndroidManifest.xml</code> file. These shortcuts are visually associated with an
- * app's launcher icon.
- * <p>Static shortcuts are published when an app is installed, and the details of these shortcuts
- * change when an app is upgraded with an updated XML file. Static shortcuts are immutable, and
- * their definitions, such as icons and labels, cannot be changed dynamically without upgrading the
- * publisher app.</li>
+ * This section describes in-depth details about each shortcut type's usage and availability.
*
- * <li>Dynamic shortcuts are published at runtime using this class's APIs. These shortcuts are
- * visually associated with an app's launcher icon. Apps can publish, update, and remove dynamic
- * shortcuts at runtime.
- * </ul>
+ * <p class="note"><b>Important security note:</b> All shortcut information is stored in
+ * <a href="/training/articles/direct-boot.html">credential encrypted storage</a>, so your app
+ * cannot access a user's shortcuts until after they've unlocked the device.
*
- * <p>Only main activities—activities that handle the {@code MAIN} action and the
- * {@code LAUNCHER} category—can have shortcuts.
- * If an app has multiple main activities, these activities have different sets
- * of shortcuts.
+ * <h4>Static and dynamic shortcuts</h4>
*
* <p>Static shortcuts and dynamic shortcuts are shown in a supported launcher when the user
- * long-presses on an app's launcher icon. Note that the actual gesture may be different
- * depending on the launcher app.
+ * performs a specific gesture. On currently-supported launchers, the gesture is a long-press on the
+ * app's launcher icon, but the actual gesture may be different on other launcher apps.
*
- * <p>Each launcher icon can have at most {@link #getMaxShortcutCountPerActivity()} number of
- * static and dynamic shortcuts combined.
+ * <p>The {@link LauncherApps} class provides APIs for launcher apps to access shortcuts.
*
+ * <h4>Pinned shortcuts</h4>
*
- * <h3>Pinning Shortcuts</h3>
+ * <p>Because pinned shortcuts appear in the launcher itself, they're always visible. A pinned
+ * shortcut is removed from the launcher only in the following situations:
+ * <ul>
+ * <li>The user removes it.
+ * <li>The publisher app associated with the shortcut is uninstalled.
+ * <li>The user performs the clear data action on the publisher app from the device's
+ * <b>Settings</b> app.
+ * </ul>
*
- * <p>Apps running in the foreground can also <em>pin</em> shortcuts at runtime, subject to user
- * permission, using this class's APIs. Each pinned shortcut is a copy of a static shortcut or a
- * dynamic shortcut. Although users can pin a shortcut multiple times, the system calls the pinning
- * API only once to complete the pinning process. Unlike static and dynamic shortcuts, pinned
- * shortcuts appear as separate icons, visually distinct from the app's launcher icon, in the
- * launcher. There is no limit to the number of pinned shortcuts that an app can create.
+ * <p>Because the system performs
+ * <a href="/guide/topics/ui/shortcuts.html#backup-and-restore">backup and restore</a> on pinned
+ * shortcuts automatically, these shortcuts' IDs should contain either stable, constant strings or
+ * server-side identifiers, rather than identifiers generated locally that might not make sense on
+ * other devices.
*
- * <p>Pinned shortcuts <strong>cannot</strong> be removed by publisher apps. They're removed only
- * when the user removes them, when the publisher app is uninstalled, or when the user performs the
- * clear data action on the publisher app from the device's <b>Settings</b> app.
+ * <h3>Shortcut display order</h3>
*
- * <p>However, the publisher app can <em>disable</em> pinned shortcuts so they cannot be started.
- * See the following sections for details.
+ * <p>When the launcher displays an app's shortcuts, they should appear in the following order:
*
- * <h3>Updating and Disabling Shortcuts</h3>
+ * <ul>
+ * <li>Static shortcuts (if {@link ShortcutInfo#isDeclaredInManifest()} is {@code true}),
+ * and then show dynamic shortcuts (if {@link ShortcutInfo#isDynamic()} is {@code true}).
+ * <li>Within each shortcut type (static and dynamic), sort the shortcuts in order of increasing
+ * rank according to {@link ShortcutInfo#getRank()}.
+ * </ul>
*
- * <p>When a dynamic shortcut is pinned, even when the publisher removes it as a dynamic shortcut,
- * the pinned shortcut will still be visible and launchable. This allows an app to have
- * more than {@link #getMaxShortcutCountPerActivity()} number of shortcuts.
+ * <p>Shortcut ranks are non-negative, sequential integers that determine the order in which
+ * shortcuts appear, assuming that the shortcuts are all in the same category. You can update ranks
+ * of existing shortcuts when you call {@link #updateShortcuts(List)},
+ * {@link #addDynamicShortcuts(List)}, or {@link #setDynamicShortcuts(List)}.
*
- * <p>For example, suppose {@link #getMaxShortcutCountPerActivity()} is 5:
- * <ol>
- * <li>A chat app publishes 5 dynamic shortcuts for the 5 most recent
- * conversations (c1, c2, ..., c5).
+ * <p class="note"><b>Note:</b> Ranks are auto-adjusted so that they're unique for each type of
+ * shortcut (static or dynamic). For example, if there are 3 dynamic shortcuts with ranks 0, 1 and
+ * 2, adding another dynamic shortcut with a rank of 1 represents a request to place this shortcut
+ * at the second position. In response, the third and fourth shortcuts move closer to the bottom of
+ * the shortcut list, with their ranks changing to 2 and 3, respectively.
*
- * <li>The user pins all 5 of the shortcuts.
- *
- * <li>Later, the user has started 3 additional conversations (c6, c7, and c8),
- * so the publisher app
- * re-publishes its dynamic shortcuts. The new dynamic shortcut list is:
- * c4, c5, ..., c8.
- * The publisher app has to remove c1, c2, and c3 because it can't have more than
- * 5 dynamic shortcuts.
- *
- * <li>However, even though c1, c2, and c3 are no longer dynamic shortcuts, the pinned
- * shortcuts for these conversations are still available and launchable.
- *
- * <li>At this point, the user can access a total of 8 shortcuts that link to activities in
- * the publisher app, including the 3 pinned
- * shortcuts, even though an app can have at most 5 dynamic shortcuts.
- *
- * <li>The app can use {@link #updateShortcuts(List)} to update <em>any</em> of the existing
- * 8 shortcuts, when, for example, the chat peers' icons have changed.
- * </ol>
- * The {@link #addDynamicShortcuts(List)} and {@link #setDynamicShortcuts(List)} methods
- * can also be used
- * to update existing shortcuts with the same IDs, but they <b>cannot</b> be used
- * for updating non-dynamic, pinned shortcuts because these two methods try to convert the given
- * lists of shortcuts to dynamic shortcuts.
- *
- *
- * <h4>Disabling Static Shortcuts</h4>
- * <p>When an app is upgraded and the new version
- * no longer uses a static shortcut that appeared in the previous version, this deprecated
- * shortcut isn't published as a static shortcut.
- *
- * <p>If the deprecated shortcut is pinned, then the pinned shortcut will remain on the launcher,
- * but it's disabled automatically. When a pinned shortcut is disabled, this class's APIs cannot
- * update it.
- *
- * <h4>Disabling Dynamic Shortcuts</h4>
- * Sometimes pinned shortcuts become obsolete and may not be usable. For example, a pinned shortcut
- * to a group chat becomes unusable when the associated group chat is deleted. In cases like this,
- * apps should use {@link #disableShortcuts(List)}, which removes the specified dynamic
- * shortcuts and also makes any specified pinned shortcuts un-launchable.
- * The {@link #disableShortcuts(List, CharSequence)} method can also be used to disable shortcuts
- * and show users a custom error message when they attempt to launch the disabled shortcuts.
- *
- *
- * <h3>Publishing Static Shortcuts</h3>
- *
- * <p>
- * In order to add static shortcuts to your app, first add
- * {@code <meta-data android:name="android.app.shortcuts" />} to your main activity in
- * AndroidManifest.xml:
- * <pre>
- *<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- * package="com.example.myapplication">
- * <application ... >
- * <activity android:name="Main">
- * <intent-filter>
- * <action android:name="android.intent.action.MAIN" />
- * <category android:name="android.intent.category.LAUNCHER" />
- * </intent-filter>
- * <strong><meta-data android:name="android.app.shortcuts"
- * android:resource="@xml/shortcuts" /></strong>
- * </activity>
- * </application>
- *</manifest>
- * </pre>
- *
- * Then, define your app's static shortcuts in the <code>res/xml/shortcuts.xml</code>
- * file:
- * <pre>
- *<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
- * <shortcut
- * android:shortcutId="compose"
- * android:enabled="true"
- * android:icon="@drawable/compose_icon"
- * android:shortcutShortLabel="@string/compose_shortcut_short_label1"
- * android:shortcutLongLabel="@string/compose_shortcut_long_label1"
- * android:shortcutDisabledMessage="@string/compose_disabled_message1">
- * <intent
- * android:action="android.intent.action.VIEW"
- * android:targetPackage="com.example.myapplication"
- * android:targetClass="com.example.myapplication.ComposeActivity" />
- * <!-- If your shortcut is associated with multiple intents, include them
- * here. The last intent in the list is what the user sees when they
- * launch this shortcut. -->
- * <categories android:name="android.shortcut.conversation" />
- * </shortcut>
- * <!-- Specify more shortcuts here. -->
- *</shortcuts>
- * </pre>
+ * <h3>Options for static shortcuts</h3>
*
* The following list includes descriptions for the different attributes within a static shortcut:
* <dl>
@@ -236,9 +147,10 @@
* {@code android:action} is mandatory.
* See <a href="{@docRoot}guide/topics/ui/settings.html#Intents">Using intents</a> for the
* other supported tags.
- * You can provide multiple intents for a single shortcut so that the last defined activity is launched
- * with the other activities in the <a href="/guide/components/tasks-and-back-stack.html">back stack</a>.
- * See {@link android.app.TaskStackBuilder} for details.
+ * <p>You can provide multiple intents for a single shortcut so that the last defined activity is
+ * launched with the other activities in the
+ * <a href="/guide/components/tasks-and-back-stack.html">back stack</a>. See
+ * {@link android.app.TaskStackBuilder} for details.
* <p><b>Note:</b> String resources may not be used within an {@code <intent>} element.
* </dd>
* <dt>{@code categories}</dt>
@@ -247,337 +159,92 @@
* </dd>
* </dl>
*
- * <h3>Publishing Dynamic Shortcuts</h3>
+ * <h3>Updating shortcuts</h3>
*
- * <p>
- * Apps can publish dynamic shortcuts with {@link #setDynamicShortcuts(List)}
- * or {@link #addDynamicShortcuts(List)}. The {@link #updateShortcuts(List)} method can also be
- * used to update existing, mutable shortcuts.
- * Use {@link #removeDynamicShortcuts(List)} or {@link #removeAllDynamicShortcuts()} to remove
- * dynamic shortcuts.
- *
- * <p>The following code snippet shows how to create a single dynamic shortcut:
- * <pre>
- *ShortcutManager shortcutManager = getSystemService(ShortcutManager.class);
- *
- *ShortcutInfo shortcut = new ShortcutInfo.Builder(this, "id1")
- * .setShortLabel("Web site")
- * .setLongLabel("Open the web site")
- * .setIcon(Icon.createWithResource(context, R.drawable.icon_website))
- * .setIntent(new Intent(Intent.ACTION_VIEW,
- * Uri.parse("https://www.mysite.example.com/")))
- * .build();
- *
- *shortcutManager.setDynamicShortcuts(Arrays.asList(shortcut));
- * </pre>
- *
- * <h3>Publishing Pinned Shortcuts</h3>
- *
- * <p>Apps can pin an existing shortcut (either static or dynamic) or an entirely new shortcut to a
- * supported launcher programatically using {@link #requestPinShortcut(ShortcutInfo, IntentSender)}.
- * You pass two arguments into this method:
- *
- * <ul>
- * <li>A {@link ShortcutInfo} object – If the shortcut already exists, this object should
- * contain only the shortcut's ID. Otherwise, the new {@link ShortcutInfo} object must contain an
- * ID, an intent, and a short label for the new shortcut.
- * <li><p>A {@link android.app.PendingIntent} object – This intent represents the callback
- * that your app receives if the shortcut is successfully pinned to the device's launcher.
- * <p><b>Note:</b> If the user doesn't allow the shortcut to be pinned to the launcher, the
- * pinning process fails, and the {@link Intent} object that is passed into this
- * {@link android.app.PendingIntent} object isn't executed.
- * <div class="note"><p><b>Note:</b> Due to background execution limits introduced in Android
- * {@link VERSION_CODES#O}, it's best to use a
- * <a href="{@docRoot}guide/components/broadcasts.html#manifest-declared_receivers">
- * manifest-declared receiver</a> to receive a callback.
- * <p>Also, to prevent other apps from invoking the receiver, add the attribute assignment
- * <code>android:exported="false"</code> to the receiver's manifest entry.</p></div>
- * </ul>
- *
- * The following code snippet shows how to pin a single shortcut that already exists and is enabled:
- *
- * <pre>
- *ShortcutManager mShortcutManager =
- * context.getSystemService(ShortcutManager.class);
- *
- *if (mShortcutManager.isRequestPinShortcutSupported()) {
- *
- * // This example defines a new shortcut; that is, this shortcut hasn't
- * // been published before.
- * ShortcutInfo pinShortcutInfo = new ShortcutInfo.Builder()
- * .setIcon(myIcon)
- * .setShortLabel("My awesome shortcut")
- * .setIntent(myIntent)
- * .build();
- *
- * PendingIntent resultPendingIntent = null;
- *
- * // Create the following Intent and PendingIntent objects only if your app
- * // needs to be notified that the user allowed the shortcut to be pinned.
- * // Use a boolean value, such as "appNeedsNotifying", to define this behavior.
- * if (appNeedsNotifying) {
- * // We assume here the app has a manifest-declared receiver "MyReceiver".
- * Intent pinnedShortcutCallbackIntent = new Intent(context, MyReceiver.class);
- *
- * // Configure the intent so that your app's broadcast receiver gets
- * // the callback successfully.
- * PendingIntent successCallback = PendingIntent.createBroadcast(context, 0,
- * pinnedShortcutCallbackIntent);
- *
- * resultPendingIntent = successCallback.getIntentSender();
- * }
- *
- * mShortcutManager.requestPinShortcut(pinShortcutInfo, resultPendingIntent);
- *}
- * </pre>
- *
- * <p class="note"><strong>Note:</strong> As you add logic in your app to make requests to pin
- * shortcuts, keep in mind that not all launchers support pinning of shortcuts. To determine whether
- * your app can complete this process on a particular device, check the return value of
- * {@link #isRequestPinShortcutSupported()}. Based on this return value, you might decide to hide
- * the option in your app that allows users to pin a shortcut.
- *
- * <p class="note"><strong>Note:</strong> See also the support library APIs
- * {@link android.support.v4.content.pm.ShortcutManagerCompat#isRequestPinShortcutSupported(
- * Context)} and
- * {@link android.support.v4.content.pm.ShortcutManagerCompat#requestPinShortcut(
- * Context, ShortcutInfoCompat, IntentSender)}, which works on Android versions lower than
- * {@link VERSION_CODES#O} by falling back to the deprecated private intent
- * {@code com.android.launcher.action.INSTALL_SHORTCUT}.
- *
- * <h4>Custom Activity for Pinning Shortcuts</h4>
- *
- * <p>You can also create a specialized activity that helps users create shortcuts, complete with
- * custom options and a confirmation button. In your app's manifest file, add
- * {@link Intent#ACTION_CREATE_SHORTCUT} to the activity's <code><intent-filter></code>
- * element, as shown in the following snippet:
- *
- * <pre>
- *<manifest>
- * ...
- * <application>
- * <activity android:name="com.example.MyCustomPromptToPinShortcut" ... >
- * <intent-filter
- * action android:name="android.intent.action.ACTION_CREATE_SHORTCUT">
- * ...
- * </intent-filter>
- * </activity>
- * ...
- * </application>
- *</manifest>
- * </pre>
- *
- * <p>When you use this specialized activity in your app, the following sequence of steps takes
- * place:</p>
- *
+ * <p>As an example, suppose {@link #getMaxShortcutCountPerActivity()} is 5:
* <ol>
- * <li>The user attempts to create a shortcut, triggering the system to start the specialized
- * activity.</li>
- * <li>The user sets options for the shortcut.</li>
- * <li>The user selects the confirmation button, allowing your app to create the shortcut using
- * the {@link #createShortcutResultIntent(ShortcutInfo)} method. This method returns an
- * {@link Intent}, which your app relays back to the previously-executing activity using
- * {@link Activity#setResult(int)}.</li>
- * <li>Your app calls {@link Activity#finish()} on the activity used for creating the customized
- * shortcut.</li>
+ * <li>A chat app publishes 5 dynamic shortcuts for the 5 most recent
+ * conversations (c1, c2, ..., c5).
+ *
+ * <li>The user pins all 5 of the shortcuts.
+ *
+ * <li>Later, the user has started 3 additional conversations (c6, c7, and c8),
+ * so the publisher app
+ * re-publishes its dynamic shortcuts. The new dynamic shortcut list is:
+ * c4, c5, ..., c8.
+ * The publisher app has to remove c1, c2, and c3 because it can't have more than
+ * 5 dynamic shortcuts.
+ *
+ * <li>However, even though c1, c2, and c3 are no longer dynamic shortcuts, the pinned
+ * shortcuts for these conversations are still available and launchable.
+ *
+ * <li>At this point, the user can access a total of 8 shortcuts that link to activities in
+ * the publisher app, including the 3 pinned shortcuts, even though an app can have at most 5
+ * dynamic shortcuts.
+ *
+ * <li>The app can use {@link #updateShortcuts(List)} to update <em>any</em> of the existing
+ * 8 shortcuts, when, for example, the chat peers' icons have changed.
+ * <p>The {@link #addDynamicShortcuts(List)} and {@link #setDynamicShortcuts(List)} methods
+ * can also be used to update existing shortcuts with the same IDs, but they <b>cannot</b> be
+ * used for updating non-dynamic, pinned shortcuts because these 2 methods try to convert the
+ * given lists of shortcuts to dynamic shortcuts.
* </ol>
*
- * <h3>Shortcut Intents</h3>
+ * <h3>Shortcut intents</h3>
+ *
* <p>
* Dynamic shortcuts can be published with any set of {@link Intent#addFlags Intent} flags.
* Typically, {@link Intent#FLAG_ACTIVITY_CLEAR_TASK} is specified, possibly along with other
* flags; otherwise, if the app is already running, the app is simply brought to
* the foreground, and the target activity may not appear.
*
- * <p>The {@link ShortcutInfo.Builder#setIntents(Intent[])} method can be used instead of
- * {@link ShortcutInfo.Builder#setIntent(Intent)} with {@link android.app.TaskStackBuilder}
- * in order to launch an activity with other activities in the back stack.
- * When the user selects a shortcut to load an activity with a back stack,
- * then presses the back key, a parent activity from the same app will be shown
- * instead of the user being navigated back to the launcher.
- *
- * <p>Static shortcuts can also have multiple intents to achieve the same effect.
- * In order to associate multiple {@link Intent} objects with a shortcut, simply list multiple
- * <code><intent></code> elements within a single <code><shortcut></code> element.
- * The last intent specifies what the user sees when they launch a shortcut.
- *
* <p>Static shortcuts <b>cannot</b> have custom intent flags.
* The first intent of a static shortcut will always have {@link Intent#FLAG_ACTIVITY_NEW_TASK}
- * and {@link Intent#FLAG_ACTIVITY_CLEAR_TASK} set.
- * This means, when the app is already running, all the existing activities will be
- * destroyed when a static shortcut is launched.
- * If this behavior is not desirable, you can use a <em>trampoline activity</em>,
- * or an invisible activity that starts another activity in {@link Activity#onCreate},
- * then calls {@link Activity#finish()}.
- * The first activity should include an attribute setting
- * of {@code android:taskAffinity=""} in the app's <code>AndroidManifest.xml</code>
- * file, and the intent within the static shortcut should point at this first activity.
+ * and {@link Intent#FLAG_ACTIVITY_CLEAR_TASK} set. This means, when the app is already running, all
+ * the existing activities in your app will be destroyed when a static shortcut is launched.
+ * If this behavior is not desirable, you can use a <em>trampoline activity</em>, or an invisible
+ * activity that starts another activity in {@link Activity#onCreate}, then calls
+ * {@link Activity#finish()}:
+ * <ol>
+ * <li>In the <code>AndroidManifest.xml</code> file, the trampoline activity should include the
+ * attribute assignment {@code android:taskAffinity=""}.
+ * <li>In the shortcuts resource file, the intent within the static shortcut should point at
+ * the trampoline activity.
+ * </ol>
*
+ * <h3>Handling system locale changes</h3>
*
- * <h3>Showing New Information in a Shortcut</h3>
- * <p>
- * In order to avoid confusion, you should not use {@link #updateShortcuts(List)} to update
- * a shortcut so that it contains conceptually different information.
+ * <p>Apps should update dynamic and pinned shortcuts when the system locale changes using the
+ * {@link Intent#ACTION_LOCALE_CHANGED} broadcast. When the system locale changes,
+ * <a href="/guide/topics/ui/shortcuts.html#rate-limit">rate limiting</a> is reset, so even
+ * background apps can add and update dynamic shortcuts until the rate limit is reached again.
*
- * <p>For example, a phone app may publish the most frequently called contact as a dynamic
- * shortcut. Over time, this contact may change. When it does, the app should
- * represent the changed contact with a new shortcut that contains a different ID, using either
- * {@link #setDynamicShortcuts(List)} or {@link #addDynamicShortcuts(List)}, rather than updating
- * the existing shortcut with {@link #updateShortcuts(List)}.
- * This is because when the shortcut is pinned, changing
- * it to reference a different contact will likely confuse the user.
+ * <h3>Shortcut limits</h3>
*
- * <p>On the other hand, when the
- * contact's information has changed, such as the name or picture, the app should
- * use {@link #updateShortcuts(List)} so that the pinned shortcut is updated too.
+ * <p>Only main activities—activities that handle the {@code MAIN} action and the
+ * {@code LAUNCHER} category—can have shortcuts. If an app has multiple main activities, you
+ * need to define the set of shortcuts for <em>each</em> activity.
*
+ * <p>Each launcher icon can have at most {@link #getMaxShortcutCountPerActivity()} number of
+ * static and dynamic shortcuts combined. There is no limit to the number of pinned shortcuts that
+ * an app can create.
*
- * <h3>Shortcut Display Order</h3>
- * When the launcher displays the shortcuts that are associated with a particular launcher icon,
- * the shortcuts should appear in the following order:
- * <ul>
- * <li>First show static shortcuts
- * (if {@link ShortcutInfo#isDeclaredInManifest()} is {@code true}),
- * and then show dynamic shortcuts (if {@link ShortcutInfo#isDynamic()} is {@code true}).
- * <li>Within each category of shortcuts (static and dynamic), sort the shortcuts in order
- * of increasing rank according to {@link ShortcutInfo#getRank()}.
- * </ul>
- * <p>Shortcut ranks are non-negative, sequential integers
- * that determine the order in which shortcuts appear, assuming that the shortcuts are all in
- * the same category.
- * Ranks of existing shortcuts can be updated with
- * {@link #updateShortcuts(List)}. You can also use {@link #addDynamicShortcuts(List)} and
- * {@link #setDynamicShortcuts(List)}.
+ * <p>When a dynamic shortcut is pinned, even when the publisher removes it as a dynamic shortcut,
+ * the pinned shortcut is still visible and launchable. This allows an app to have more than
+ * {@link #getMaxShortcutCountPerActivity()} number of shortcuts.
*
- * <p>Ranks are auto-adjusted so that they're unique for each target activity in each category
- * (static or dynamic). For example, if there are 3 dynamic shortcuts with ranks 0, 1 and 2,
- * adding another dynamic shortcut with a rank of 1 represents a request to place this shortcut at
- * the second position.
- * In response, the third and fourth shortcuts move closer to the bottom of the shortcut list,
- * with their ranks changing to 2 and 3, respectively.
+ * <h4>Rate limiting</h4>
*
- * <h3>Rate Limiting</h3>
+ * <p>When <a href="/guide/topics/ui/shortcuts.html#rate-limit">rate limiting</a> is active,
+ * {@link #isRateLimitingActive()} returns {@code true}.
*
- * <p>
- * Calls to {@link #setDynamicShortcuts(List)}, {@link #addDynamicShortcuts(List)}, and
- * {@link #updateShortcuts(List)} may be rate-limited when called by <em>background apps</em>, or
- * apps with no foreground activity or service. When you attempt to call these methods
- * from a background app after exceeding the rate limit, these APIs return {@code false}.
- *
- * <p>Apps with a foreground activity or service are not rate-limited.
- *
- * <p>Rate-limiting is reset upon certain events, so that even background apps
- * can call these APIs until the rate limit is reached again.
- * These events include the following:
+ * <p>Rate limiting is reset upon certain events, so even background apps can call these APIs until
+ * the rate limit is reached again. These events include the following:
* <ul>
* <li>An app comes to the foreground.
* <li>The system locale changes.
* <li>The user performs the <strong>inline reply</strong> action on a notification.
* </ul>
- *
- * <p>When rate-limiting is active, {@link #isRateLimitingActive()} returns {@code true}.
- *
- * <h4>Resetting rate-limiting for testing</h4>
- *
- * <p>
- * If your app is rate-limited during development or testing, you can use the
- * <strong>Reset ShortcutManager rate-limiting</strong> development option or
- * the following {@code adb} command to reset it:
- * <pre class="no-pretty-print">
- *$ adb shell cmd shortcut reset-throttling [ --user USER-ID ]
- * </pre>
- *
- * <h3>Handling System Locale Changes</h3>
- *
- * <p>
- * Apps should update dynamic and pinned shortcuts when the system locale changes
- * using the {@link Intent#ACTION_LOCALE_CHANGED} broadcast.
- *
- * <p>When the system locale changes, rate-limiting is reset, so even background apps
- * can add and update dynamic shortcuts until the rate limit is reached again.
- *
- *
- * <h3>Backup and Restore</h3>
- *
- * <p>
- * When an app has the {@code android:allowBackup="true"} attribute assignment included
- * in its <code>AndroidManifest.xml</code> file, pinned shortcuts are
- * backed up automatically and are restored when the user sets up a new device.
- *
- * <h4>Categories of shortcuts that are backed up</h4>
- *
- * <ul>
- * <li>Pinned shortcuts are backed up. Bitmap icons are not backed up by the system,
- * so launcher apps should back them up and restore them so that the user still sees icons
- * for pinned shortcuts on the launcher. Apps can always use
- * {@link #updateShortcuts(List)} to re-publish icons.
- *
- * <li>Static shortcuts aren't backed up, but when an app is re-installed on a new
- * device, they are re-published from the <code>AndroidManifest.xml</code> file.
- *
- * <li>Dynamic shortcuts <b>aren't</b> backed up.
- * </ul>
- *
- * <p>Because dynamic shortcuts are not restored, it is recommended that apps check
- * currently-published dynamic shortcuts using {@link #getDynamicShortcuts()}
- * each time they are launched, and they should re-publish
- * dynamic shortcuts when necessary.
- *
- * <pre>
- *public class MainActivity extends Activity {
- * public void onCreate(Bundle savedInstanceState) {
- * super.onCreate(savedInstanceState);
- * ShortcutManager shortcutManager =
- * getSystemService(ShortcutManager.class);
- *
- * if (shortcutManager.getDynamicShortcuts().size() == 0) {
- * // Application restored. Need to re-publish dynamic shortcuts.
- * if (shortcutManager.getPinnedShortcuts().size() > 0) {
- * // Pinned shortcuts have been restored. Use
- * // updateShortcuts() to make sure they contain
- * // up-to-date information.
- * }
- * }
- * }
- * // ...
- *}
- * </pre>
- *
- *
- * <h4>Backup/restore and shortcut IDs</h4>
- * <p>
- * Because pinned shortcuts are backed up and restored on new devices, shortcut IDs
- * should contain either stable, constant strings or server-side identifiers,
- * rather than identifiers generated locally that might not make sense on other devices.
- *
- *
- * <h3>Report Shortcut Usage and Prediction</h3>
- * <p>
- * Launcher apps may be capable of predicting which shortcuts will most likely be
- * used at a given time by examining the shortcut usage history data.
- *
- * <p>In order to provide launchers with such data, publisher apps should
- * report the shortcuts that are used with {@link #reportShortcutUsed(String)}
- * when a shortcut is selected,
- * <b>or when an action equivalent to a shortcut is taken by the user even if it wasn't started
- * with the shortcut</b>.
- *
- * <p>For example, suppose a navigation app supports "navigate to work" as a shortcut.
- * It should then report when the user selects this shortcut <b>and</b> when the user chooses
- * to navigate to work within the app itself.
- * This helps the launcher app
- * learn that the user wants to navigate to work at a certain time every
- * weekday, and it can then show this shortcut in a suggestion list at the right time.
- *
- * <h3>Launcher API</h3>
- *
- * The {@link LauncherApps} class provides APIs for launcher apps to access shortcuts.
- *
- *
- * <h3>Direct Boot and Shortcuts</h3>
- *
- * All shortcut information is stored in credential encrypted storage, so no shortcuts can be
- * accessed when the user is locked.
*/
@SystemService(Context.SHORTCUT_SERVICE)
public class ShortcutManager {
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 48123fe..744ee8e 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -840,8 +840,8 @@
* In order to support the always-on feature, an app has to
* <ul>
* <li>target {@link VERSION_CODES#N API 24} or above, and
- * <li>not opt out through the {@link VpnService#METADATA_SUPPORTS_ALWAYS_ON} meta-data
- * field.
+ * <li>not opt out through the {@link VpnService#SERVICE_META_DATA_SUPPORTS_ALWAYS_ON}
+ * meta-data field.
* </ul>
*
* @param userId The identifier of the user for whom the VPN app is installed.
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index 7fb0c47..185b181 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -152,9 +152,10 @@
* </service>
* } </pre>
*
- * <p>This meta-data field defaults to {@code true} if absent.
+ * <p>This meta-data field defaults to {@code true} if absent. It will only have effect on
+ * {@link android.os.Build.VERSION_CODES#O_MR1} or higher.
*/
- public static final String METADATA_SUPPORTS_ALWAYS_ON =
+ public static final String SERVICE_META_DATA_SUPPORTS_ALWAYS_ON =
"android.net.VpnService.SUPPORTS_ALWAYS_ON";
/**
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index b916b43..e6e1da4 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -220,6 +220,21 @@
void unregisterTetheringStatsProvider(ITetheringStatsProvider provider);
/**
+ * Reports that a tethering provider has reached a data limit.
+ *
+ * Currently triggers a global alert, which causes NetworkStatsService to poll counters and
+ * re-evaluate data usage.
+ *
+ * This does not take an interface name because:
+ * 1. The tethering offload stats provider cannot reliably determine the interface on which the
+ * limit was reached, because the HAL does not provide it.
+ * 2. Firing an interface-specific alert instead of a global alert isn't really useful since in
+ * all cases of interest, the system responds to both in the same way - it polls stats, and
+ * then notifies NetworkPolicyManagerService of the fact.
+ */
+ void tetherLimitReached(ITetheringStatsProvider provider);
+
+ /**
** PPPD
**/
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 78cdf5d..2c1f734 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -659,6 +659,8 @@
*
* @see #isSharedBufferModeEnabled()
* @see #setAutoRefreshEnabled(boolean)
+ *
+ * @hide
*/
public void setSharedBufferModeEnabled(boolean enabled) {
if (mIsSharedBufferModeEnabled != enabled) {
@@ -676,6 +678,8 @@
* @return True if shared buffer mode is enabled on this surface, false otherwise
*
* @see #setSharedBufferModeEnabled(boolean)
+ *
+ * @hide
*/
public boolean isSharedBufferModeEnabled() {
return mIsSharedBufferModeEnabled;
@@ -699,6 +703,8 @@
*
* @see #isAutoRefreshEnabled()
* @see #setSharedBufferModeEnabled(boolean)
+ *
+ * @hide
*/
public void setAutoRefreshEnabled(boolean enabled) {
if (mIsAutoRefreshEnabled != enabled) {
@@ -713,6 +719,8 @@
/**
* @return True if auto-refresh is enabled on this surface, false otherwise
+ *
+ * @hide
*/
public boolean isAutoRefreshEnabled() {
return mIsAutoRefreshEnabled;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2b4015f..8a9b14e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8078,10 +8078,6 @@
boolean forAutofill, @AutofillFlags int flags) {
if (forAutofill) {
structure.setAutofillId(getAutofillId());
- if (!isLaidOut()) {
- Log.w(VIEW_LOG_TAG, "dispatchProvideAutofillStructure(): not laid out, ignoring");
- return;
- }
onProvideAutofillStructure(structure, flags);
onProvideAutofillVirtualStructure(structure, flags);
} else if (!isAssistBlocked()) {
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index ecdfa3f..18b7334 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3400,6 +3400,13 @@
if (childrenCount <= 0) {
return;
}
+
+ if (!isLaidOut()) {
+ Log.v(VIEW_LOG_TAG, "dispatchProvideStructure(): not laid out, ignoring "
+ + childrenCount + " children of " + getAccessibilityViewId());
+ return;
+ }
+
structure.setChildCount(childrenCount);
ArrayList<View> preorderedList = buildOrderedChildList();
boolean customOrder = preorderedList == null
@@ -3476,6 +3483,13 @@
if (structure.getChildCount() != 0) {
return;
}
+
+ if (!isLaidOut()) {
+ Log.v(VIEW_LOG_TAG, "dispatchProvideAutofillStructure(): not laid out, ignoring "
+ + mChildrenCount + " children of " + getAutofillId());
+ return;
+ }
+
final ChildListForAutoFill children = getChildrenForAutofill(flags);
final int childrenCount = children.size();
structure.setChildCount(childrenCount);
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index a0d9099..29e5523 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -1339,25 +1339,6 @@
}
/**
- * Dismiss the Autofill UI, even if associated with other sessions.
- *
- * <p>Typically called when a new activity starts so it can hide the existing Save UI (if any).
- *
- * @hide
- */
- public void dismissUi() {
- if (sVerbose) Log.v(TAG, "dismissUi()");
-
- if (mService == null) return;
-
- try {
- mService.dismissUi();
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
- }
-
- /**
* View tracking information. Once all tracked views become invisible the session is finished.
*/
private class TrackedViews {
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index aa8e19a..627afa7 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -49,5 +49,4 @@
void disableOwnedAutofillServices(int userId);
boolean isServiceSupported(int userId);
boolean isServiceEnabled(int userId, String packageName);
- void dismissUi();
}
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 8094bfc..dfb3642 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -524,12 +524,13 @@
void setAutoFillChangeListener(OnDateChangedListener onDateChangedListener);
void updateDate(int year, int month, int dayOfMonth);
- void updateDate(long date);
int getYear();
int getMonth();
int getDayOfMonth();
- long getDate();
+
+ void autofill(AutofillValue value);
+ AutofillValue getAutofillValue();
void setFirstDayOfWeek(int firstDayOfWeek);
int getFirstDayOfWeek();
@@ -572,6 +573,7 @@
// The context
protected Context mContext;
+ // NOTE: when subclasses change this variable, they must call resetAutofilledValue().
protected Calendar mCurrentDate;
// The current locale
@@ -582,6 +584,11 @@
protected OnDateChangedListener mAutoFillChangeListener;
protected ValidationCallback mValidationCallback;
+ // The value that was passed to autofill() - it must be stored because it getAutofillValue()
+ // must return the exact same value that was autofilled, otherwise the widget will not be
+ // properly highlighted after autofill().
+ private long mAutofilledValue;
+
public AbstractDatePickerDelegate(DatePicker delegator, Context context) {
mDelegator = delegator;
mContext = context;
@@ -612,16 +619,38 @@
}
@Override
- public void updateDate(long date) {
- Calendar cal = Calendar.getInstance(mCurrentLocale);
- cal.setTimeInMillis(date);
+ public final void autofill(AutofillValue value) {
+ if (value == null || !value.isDate()) {
+ Log.w(LOG_TAG, value + " could not be autofilled into " + this);
+ return;
+ }
+
+ final long time = value.getDateValue();
+
+ final Calendar cal = Calendar.getInstance(mCurrentLocale);
+ cal.setTimeInMillis(time);
updateDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH),
cal.get(Calendar.DAY_OF_MONTH));
+
+ // Must set mAutofilledValue *after* calling subclass method to make sure the value
+ // returned by getAutofillValue() matches it.
+ mAutofilledValue = time;
}
@Override
- public long getDate() {
- return mCurrentDate.getTimeInMillis();
+ public final AutofillValue getAutofillValue() {
+ final long time = mAutofilledValue != 0
+ ? mAutofilledValue
+ : mCurrentDate.getTimeInMillis();
+ return AutofillValue.forDate(time);
+ }
+
+ /**
+ * This method must be called every time the value of the year, month, and/or day is
+ * changed by a subclass method.
+ */
+ protected void resetAutofilledValue() {
+ mAutofilledValue = 0;
}
protected void onValidationChanged(boolean valid) {
@@ -777,12 +806,7 @@
public void autofill(AutofillValue value) {
if (!isEnabled()) return;
- if (!value.isDate()) {
- Log.w(LOG_TAG, value + " could not be autofilled into " + this);
- return;
- }
-
- mDelegate.updateDate(value.getDateValue());
+ mDelegate.autofill(value);
}
@Override
@@ -792,6 +816,6 @@
@Override
public AutofillValue getAutofillValue() {
- return isEnabled() ? AutofillValue.forDate(mDelegate.getDate()) : null;
+ return isEnabled() ? mDelegate.getAutofillValue() : null;
}
}
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index 636519b..60b4757 100755
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -368,12 +368,9 @@
}
@Override
- public void init(int year, int monthOfYear, int dayOfMonth,
+ public void init(int year, int month, int dayOfMonth,
DatePicker.OnDateChangedListener callBack) {
- mCurrentDate.set(Calendar.YEAR, year);
- mCurrentDate.set(Calendar.MONTH, monthOfYear);
- mCurrentDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
-
+ setDate(year, month, dayOfMonth);
onDateChanged(false, false);
mOnDateChangedListener = callBack;
@@ -381,11 +378,15 @@
@Override
public void updateDate(int year, int month, int dayOfMonth) {
+ setDate(year, month, dayOfMonth);
+ onDateChanged(false, true);
+ }
+
+ private void setDate(int year, int month, int dayOfMonth) {
mCurrentDate.set(Calendar.YEAR, year);
mCurrentDate.set(Calendar.MONTH, month);
mCurrentDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
-
- onDateChanged(false, true);
+ resetAutofilledValue();
}
private void onDateChanged(boolean fromUser, boolean callbackToClient) {
diff --git a/core/java/android/widget/DatePickerSpinnerDelegate.java b/core/java/android/widget/DatePickerSpinnerDelegate.java
index 4f9316f..dba74b1 100644
--- a/core/java/android/widget/DatePickerSpinnerDelegate.java
+++ b/core/java/android/widget/DatePickerSpinnerDelegate.java
@@ -504,6 +504,7 @@
private void setDate(int year, int month, int dayOfMonth) {
mCurrentDate.set(year, month, dayOfMonth);
+ resetAutofilledValue();
if (mCurrentDate.before(mMinDate)) {
mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
} else if (mCurrentDate.after(mMaxDate)) {
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index de289bb..ae6881e 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -366,8 +366,11 @@
void setMinute(@IntRange(from = 0, to = 59) int minute);
int getMinute();
- void setDate(long date);
- long getDate();
+ void setDate(@IntRange(from = 0, to = 23) int hour,
+ @IntRange(from = 0, to = 59) int minute);
+
+ void autofill(AutofillValue value);
+ AutofillValue getAutofillValue();
void setIs24Hour(boolean is24Hour);
boolean is24Hour();
@@ -422,6 +425,11 @@
protected OnTimeChangedListener mOnTimeChangedListener;
protected OnTimeChangedListener mAutoFillChangeListener;
+ // The value that was passed to autofill() - it must be stored because it getAutofillValue()
+ // must return the exact same value that was autofilled, otherwise the widget will not be
+ // properly highlighted after autofill().
+ private long mAutofilledValue;
+
public AbstractTimePickerDelegate(@NonNull TimePicker delegator, @NonNull Context context) {
mDelegator = delegator;
mContext = context;
@@ -439,19 +447,41 @@
}
@Override
- public void setDate(long date) {
- Calendar cal = Calendar.getInstance(mLocale);
- cal.setTimeInMillis(date);
- setHour(cal.get(Calendar.HOUR_OF_DAY));
- setMinute(cal.get(Calendar.MINUTE));
+ public final void autofill(AutofillValue value) {
+ if (value == null || !value.isDate()) {
+ Log.w(LOG_TAG, value + " could not be autofilled into " + this);
+ return;
+ }
+
+ final long time = value.getDateValue();
+
+ final Calendar cal = Calendar.getInstance(mLocale);
+ cal.setTimeInMillis(time);
+ setDate(cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE));
+
+ // Must set mAutofilledValue *after* calling subclass method to make sure the value
+ // returned by getAutofillValue() matches it.
+ mAutofilledValue = time;
}
@Override
- public long getDate() {
- Calendar cal = Calendar.getInstance(mLocale);
+ public final AutofillValue getAutofillValue() {
+ if (mAutofilledValue != 0) {
+ return AutofillValue.forDate(mAutofilledValue);
+ }
+
+ final Calendar cal = Calendar.getInstance(mLocale);
cal.set(Calendar.HOUR_OF_DAY, getHour());
cal.set(Calendar.MINUTE, getMinute());
- return cal.getTimeInMillis();
+ return AutofillValue.forDate(cal.getTimeInMillis());
+ }
+
+ /**
+ * This method must be called every time the value of the hour and/or minute is changed by
+ * a subclass method.
+ */
+ protected void resetAutofilledValue() {
+ mAutofilledValue = 0;
}
protected static class SavedState extends View.BaseSavedState {
@@ -532,12 +562,7 @@
public void autofill(AutofillValue value) {
if (!isEnabled()) return;
- if (!value.isDate()) {
- Log.w(LOG_TAG, value + " could not be autofilled into " + this);
- return;
- }
-
- mDelegate.setDate(value.getDateValue());
+ mDelegate.autofill(value);
}
@Override
@@ -547,6 +572,6 @@
@Override
public AutofillValue getAutofillValue() {
- return isEnabled() ? AutofillValue.forDate(mDelegate.getDate()) : null;
+ return isEnabled() ? mDelegate.getAutofillValue() : null;
}
}
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 526246b..706b0ce 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -506,19 +506,29 @@
mAmPmLayout.setLayoutParams(params);
}
+ @Override
+ public void setDate(int hour, int minute) {
+ setHourInternal(hour, FROM_EXTERNAL_API, true, false);
+ setMinuteInternal(minute, FROM_EXTERNAL_API, false);
+
+ onTimeChanged();
+ }
+
/**
* Set the current hour.
*/
@Override
public void setHour(int hour) {
- setHourInternal(hour, FROM_EXTERNAL_API, true);
+ setHourInternal(hour, FROM_EXTERNAL_API, true, true);
}
- private void setHourInternal(int hour, @ChangeSource int source, boolean announce) {
+ private void setHourInternal(int hour, @ChangeSource int source, boolean announce,
+ boolean notify) {
if (mCurrentHour == hour) {
return;
}
+ resetAutofilledValue();
mCurrentHour = hour;
updateHeaderHour(hour, announce);
updateHeaderAmPm();
@@ -532,7 +542,9 @@
}
mDelegator.invalidate();
- onTimeChanged();
+ if (notify) {
+ onTimeChanged();
+ }
}
/**
@@ -557,14 +569,15 @@
*/
@Override
public void setMinute(int minute) {
- setMinuteInternal(minute, FROM_EXTERNAL_API);
+ setMinuteInternal(minute, FROM_EXTERNAL_API, true);
}
- private void setMinuteInternal(int minute, @ChangeSource int source) {
+ private void setMinuteInternal(int minute, @ChangeSource int source, boolean notify) {
if (mCurrentMinute == minute) {
return;
}
+ resetAutofilledValue();
mCurrentMinute = minute;
updateHeaderMinute(minute, true);
@@ -576,7 +589,9 @@
}
mDelegator.invalidate();
- onTimeChanged();
+ if (notify) {
+ onTimeChanged();
+ }
}
/**
@@ -870,7 +885,7 @@
valueChanged = true;
}
final boolean isTransition = mAllowAutoAdvance && autoAdvance;
- setHourInternal(newValue, FROM_RADIAL_PICKER, !isTransition);
+ setHourInternal(newValue, FROM_RADIAL_PICKER, !isTransition, true);
if (isTransition) {
setCurrentItemShowing(MINUTE_INDEX, true, false);
@@ -882,7 +897,7 @@
if (getMinute() != newValue) {
valueChanged = true;
}
- setMinuteInternal(newValue, FROM_RADIAL_PICKER);
+ setMinuteInternal(newValue, FROM_RADIAL_PICKER, true);
break;
}
@@ -897,10 +912,10 @@
public void onValueChanged(int pickerType, int newValue) {
switch (pickerType) {
case TextInputTimePickerView.HOURS:
- setHourInternal(newValue, FROM_INPUT_PICKER, false);
+ setHourInternal(newValue, FROM_INPUT_PICKER, false, true);
break;
case TextInputTimePickerView.MINUTES:
- setMinuteInternal(newValue, FROM_INPUT_PICKER);
+ setMinuteInternal(newValue, FROM_INPUT_PICKER, true);
break;
case TextInputTimePickerView.AMPM:
setAmOrPm(newValue);
diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
index 7a7d9a9..cc79b9c 100644
--- a/core/java/android/widget/TimePickerSpinnerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -284,6 +284,14 @@
}
@Override
+ public void setDate(int hour, int minute) {
+ setCurrentHour(hour, false);
+ setCurrentMinute(minute, false);
+
+ onTimeChanged();
+ }
+
+ @Override
public void setHour(int hour) {
setCurrentHour(hour, true);
}
@@ -293,6 +301,7 @@
if (currentHour == getHour()) {
return;
}
+ resetAutofilledValue();
if (!is24Hour()) {
// convert [0,23] ordinal to wall clock display
if (currentHour >= HOURS_IN_HALF_DAY) {
@@ -328,11 +337,18 @@
@Override
public void setMinute(int minute) {
+ setCurrentMinute(minute, true);
+ }
+
+ private void setCurrentMinute(int minute, boolean notifyTimeChanged) {
if (minute == getMinute()) {
return;
}
+ resetAutofilledValue();
mMinuteSpinner.setValue(minute);
- onTimeChanged();
+ if (notifyTimeChanged) {
+ onTimeChanged();
+ }
}
@Override
diff --git a/core/java/com/android/internal/colorextraction/ColorExtractor.java b/core/java/com/android/internal/colorextraction/ColorExtractor.java
index ef98a5e..c171fa6 100644
--- a/core/java/com/android/internal/colorextraction/ColorExtractor.java
+++ b/core/java/com/android/internal/colorextraction/ColorExtractor.java
@@ -80,7 +80,7 @@
if (wallpaperManager == null) {
Log.w(TAG, "Can't listen to color changes!");
} else {
- wallpaperManager.addOnColorsChangedListener(this);
+ wallpaperManager.addOnColorsChangedListener(this, null /* handler */);
// Initialize all gradients with the current colors
Trace.beginSection("ColorExtractor#getWallpaperColors");
diff --git a/core/java/com/android/internal/colorextraction/types/Tonal.java b/core/java/com/android/internal/colorextraction/types/Tonal.java
index dbc086c..e6ef10b 100644
--- a/core/java/com/android/internal/colorextraction/types/Tonal.java
+++ b/core/java/com/android/internal/colorextraction/types/Tonal.java
@@ -111,18 +111,19 @@
final List<Color> mainColors = inWallpaperColors.getMainColors();
final int mainColorsSize = mainColors.size();
- final boolean supportsDarkText = (inWallpaperColors.getColorHints() &
- WallpaperColors.HINT_SUPPORTS_DARK_TEXT) != 0;
+ final int hints = inWallpaperColors.getColorHints();
+ final boolean supportsDarkText = (hints & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) != 0;
+ final boolean generatedFromBitmap = (hints & WallpaperColors.HINT_FROM_BITMAP) != 0;
if (mainColorsSize == 0) {
return false;
}
- // Tonal is not really a sort, it takes a color from the extracted
- // palette and finds a best fit amongst a collection of pre-defined
- // palettes. The best fit is tweaked to be closer to the source color
- // and replaces the original palette
- // Get the most preeminent, non-blacklisted color.
+ // Decide what's the best color to use.
+ // We have 2 options:
+ // • Just pick the primary color
+ // • Filter out blacklisted colors. This is useful when palette is generated
+ // automatically from a bitmap.
Color bestColor = null;
final float[] hsl = new float[3];
for (int i = 0; i < mainColorsSize; i++) {
@@ -132,7 +133,7 @@
Color.blue(colorValue), hsl);
// Stop when we find a color that meets our criteria
- if (!isBlacklisted(hsl)) {
+ if (!generatedFromBitmap || !isBlacklisted(hsl)) {
bestColor = color;
break;
}
@@ -143,6 +144,10 @@
return false;
}
+ // Tonal is not really a sort, it takes a color from the extracted
+ // palette and finds a best fit amongst a collection of pre-defined
+ // palettes. The best fit is tweaked to be closer to the source color
+ // and replaces the original palette.
int colorValue = bestColor.toArgb();
ColorUtils.RGBToHSL(Color.red(colorValue), Color.green(colorValue), Color.blue(colorValue),
hsl);
diff --git a/core/res/res/layout/autofill_save.xml b/core/res/res/layout/autofill_save.xml
index 77fa62a..50ff50f 100644
--- a/core/res/res/layout/autofill_save.xml
+++ b/core/res/res/layout/autofill_save.xml
@@ -14,94 +14,91 @@
limitations under the License.
-->
+<!-- NOTE: outer layout is required to provide proper shadow. -->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/autofill_save"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="32dp"
- android:paddingTop="16dp"
- android:elevation="32dp"
- android:background="?android:attr/colorBackground"
android:orientation="vertical">
<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/autofill_save"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
+ android:layout_marginTop="32dp"
+ android:paddingTop="16dp"
+ android:elevation="32dp"
+ android:background="?android:attr/colorBackground"
android:orientation="vertical">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:orientation="horizontal">
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:orientation="vertical">
- <TextView
- android:id="@+id/autofill_save_title"
- android:layout_width="0dp"
+ <LinearLayout
+ android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:text="@string/autofill_save_title"
- android:textSize="16sp"
- android:textColor="?android:attr/textColorPrimary"
- android:layout_weight="1">
- </TextView>
+ android:orientation="horizontal">
- <ImageView
- android:id="@+id/autofill_save_close"
- android:layout_width="wrap_content"
+ <TextView
+ android:id="@+id/autofill_save_title"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:text="@string/autofill_save_title"
+ android:textSize="16sp"
+ android:textColor="?android:attr/textColorPrimary"
+ android:layout_weight="1">
+ </TextView>
+
+ </LinearLayout>
+
+ <com.android.server.autofill.ui.CustomScrollView
+ android:id="@+id/autofill_save_custom_subtitle"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginLeft="16dp"
- android:src="@android:drawable/ic_close"
- android:alpha="0.54"
- android:background="?android:attr/selectableItemBackgroundBorderless"
- android:contentDescription="@android:string/close_button_text">
- </ImageView>
+ android:layout_marginTop="4dp"
+ android:visibility="gone"/>
</LinearLayout>
- <com.android.server.autofill.ui.CustomScrollView
- android:id="@+id/autofill_save_custom_subtitle"
- android:layout_width="match_parent"
+ <com.android.internal.widget.ButtonBarLayout
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginTop="4dp"
- android:visibility="gone"/>
+ android:layout_gravity="end"
+ android:padding="16dp"
+ android:clipToPadding="false"
+ android:layout_weight="1"
+ android:orientation="horizontal">
+
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:visibility="invisible">
+ </Space>
+
+ <Button
+ android:id="@+id/autofill_save_no"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ style="?android:attr/buttonBarButtonStyle"
+ android:text="@string/autofill_save_no">
+ </Button>
+
+ <Button
+ android:id="@+id/autofill_save_yes"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ style="@style/Widget.Material.Button.Colored"
+ android:text="@string/autofill_save_yes">
+ </Button>
+
+ </com.android.internal.widget.ButtonBarLayout>
</LinearLayout>
- <com.android.internal.widget.ButtonBarLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="end"
- android:padding="16dp"
- android:clipToPadding="false"
- android:layout_weight="1"
- android:orientation="horizontal">
-
- <Space
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:visibility="invisible">
- </Space>
-
- <Button
- android:id="@+id/autofill_save_no"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="?android:attr/buttonBarButtonStyle"
- android:text="@string/autofill_save_no">
- </Button>
-
- <Button
- android:id="@+id/autofill_save_yes"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="@style/Widget.Material.Button.Colored"
- android:text="@string/autofill_save_yes">
- <requestFocus />
- </Button>
-
- </com.android.internal.widget.ButtonBarLayout>
-
</LinearLayout>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 95aa264..98147e7 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -626,10 +626,10 @@
<bool name="config_automatic_brightness_available">false</bool>
<!-- Fast brightness animation ramp rate in brightness units per second-->
- <integer translatable="false" name="config_brightness_ramp_rate_fast">200</integer>
+ <integer translatable="false" name="config_brightness_ramp_rate_fast">180</integer>
<!-- Slow brightness animation ramp rate in brightness units per second-->
- <integer translatable="false" name="config_brightness_ramp_rate_slow">40</integer>
+ <integer translatable="false" name="config_brightness_ramp_rate_slow">60</integer>
<!-- Don't name config resources like this. It should look like config_annoyDianne -->
<bool name="config_annoy_dianne">true</bool>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 12feba9..a93e6cb 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -592,6 +592,21 @@
<!-- The size of the right icon -->
<dimen name="notification_right_icon_size">40dp</dimen>
+ <!-- The maximum height of any image in a remote view. This is applied to all images in custom remoteviews. -->
+ <dimen name="notification_custom_view_max_image_height_low_ram">208dp</dimen>
+ <!-- The maximum height of any image in a remote view. This is applied to all images in custom remoteviews. -->
+ <dimen name="notification_custom_view_max_image_width_low_ram">294dp</dimen>
+ <!-- The maximum height of a big picture in a notification. The images will be reduced to that height in case they are bigger. -->
+ <dimen name="notification_big_picture_max_height_low_ram">208dp</dimen>
+ <!-- The maximum width of a big picture in a notification. The images will be reduced to that width in case they are bigger. -->
+ <dimen name="notification_big_picture_max_width_low_ram">294dp</dimen>
+ <!-- The maximum height of a image in a media notification. The images will be reduced to that height in case they are bigger. -->
+ <dimen name="notification_media_image_max_height_low_ram">100dp</dimen>
+ <!-- The maximum width of a image in a media notification. The images will be reduced to that width in case they are bigger.-->
+ <dimen name="notification_media_image_max_width_low_ram">100dp</dimen>
+ <!-- The size of the right icon image when on low ram -->
+ <dimen name="notification_right_icon_size_low_ram">40dp</dimen>
+
<!-- Max width/height of the autofill data set picker as a fraction of the screen width/height -->
<dimen name="autofill_dataset_picker_max_size">90%</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 061413c..af08e24 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2900,7 +2900,6 @@
<java-symbol type="id" name="autofill_save_title" />
<java-symbol type="id" name="autofill_save_no" />
<java-symbol type="id" name="autofill_save_yes" />
- <java-symbol type="id" name="autofill_save_close" />
<java-symbol type="string" name="autofill_error_cannot_autofill" />
<java-symbol type="string" name="autofill_picker_no_suggestions" />
<java-symbol type="plurals" name="autofill_picker_some_suggestions" />
@@ -2932,6 +2931,14 @@
<java-symbol type="dimen" name="notification_custom_view_max_image_height"/>
<java-symbol type="dimen" name="notification_custom_view_max_image_width"/>
+ <java-symbol type="dimen" name="notification_big_picture_max_height_low_ram"/>
+ <java-symbol type="dimen" name="notification_big_picture_max_width_low_ram"/>
+ <java-symbol type="dimen" name="notification_media_image_max_width_low_ram"/>
+ <java-symbol type="dimen" name="notification_media_image_max_height_low_ram"/>
+ <java-symbol type="dimen" name="notification_right_icon_size_low_ram"/>
+ <java-symbol type="dimen" name="notification_custom_view_max_image_height_low_ram"/>
+ <java-symbol type="dimen" name="notification_custom_view_max_image_width_low_ram"/>
+
<!-- Accessibility fingerprint gestures -->
<java-symbol type="string" name="capability_title_canCaptureFingerprintGestures" />
<java-symbol type="string" name="capability_desc_canCaptureFingerprintGestures" />
diff --git a/packages/InputDevices/res/raw/keyboard_layout_persian.kcm b/packages/InputDevices/res/raw/keyboard_layout_persian.kcm
new file mode 100644
index 0000000..e7dd6c6
--- /dev/null
+++ b/packages/InputDevices/res/raw/keyboard_layout_persian.kcm
@@ -0,0 +1,501 @@
+# Copyright (C) 2017 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.
+
+
+
+type FULL
+
+### Basic QWERTY keys ###
+
+key A {
+ label: '\u0634'
+ base: '\u0634'
+ shift, capslock: '\u0624'
+ ctrl, alt, meta: none
+}
+
+key B {
+ label: '\u0630'
+ base: '\u0630'
+ shift, capslock: '\u200C'
+ ctrl, alt, meta: none
+}
+
+key C {
+ label: '\u0632'
+ base: '\u0632'
+ shift, capslock: '\u0698'
+ ctrl, alt, meta: none
+}
+
+key D {
+ label: '\u06CC'
+ base: '\u06CC'
+ shift, capslock: '\u064A'
+ ctrl, alt, meta: none
+}
+
+key E {
+ label: '\u062B'
+ base: '\u062B'
+ shift, capslock: '\u064D'
+ ctrl, alt, meta: none
+}
+
+key F {
+ label: '\u0628'
+ base: '\u0628'
+ shift, capslock: '\u0625'
+ ctrl, alt, meta: none
+}
+
+key G {
+ label: '\u0644'
+ base: '\u0644'
+ shift, capslock: '\u0623'
+ ctrl, alt, meta: none
+}
+
+key H {
+ label: '\u0627'
+ base: '\u0627'
+ shift, capslock: '\u0622'
+ ctrl, alt, meta: none
+}
+
+key I {
+ label: '\u0647'
+ base: '\u0647'
+ shift, capslock: '\u0651'
+ ctrl, alt, meta: none
+}
+
+key J {
+ label: '\u062A'
+ base: '\u062A'
+ shift, capslock: '\u0629'
+ ctrl, alt, meta: none
+}
+
+key K {
+ label: '\u0646'
+ base: '\u0646'
+ shift, capslock: '\u00AB'
+ ctrl, alt, meta: none
+}
+
+key L {
+ label: '\u0645'
+ base: '\u0645'
+ shift, capslock: '\u00BB'
+ ctrl, alt, meta: none
+}
+
+key M {
+ label: '\u067E'
+ base: '\u067E'
+ shift, capslock: '\u0621'
+ ctrl, alt, meta: none
+}
+
+key N {
+ label: '\u062F'
+ base: '\u062F'
+ shift, capslock: '\u0654'
+ ctrl, alt, meta: none
+}
+
+key O {
+ label: '\u062E'
+ base: '\u062E'
+ shift, capslock: ']'
+ ctrl, alt, meta: none
+}
+
+key P {
+ label: '\u062D'
+ base: '\u062D'
+ shift, capslock: '['
+ ctrl, alt, meta: none
+}
+
+key Q {
+ label: '\u0636'
+ base: '\u0636'
+ shift, capslock: '\u0652'
+ ctrl, alt, meta: none
+}
+
+key R {
+ label: '\u0642'
+ base: '\u0642'
+ shift, capslock: '\u064B'
+ ctrl, alt, meta: none
+}
+
+key S {
+ label: '\u0633'
+ base: '\u0633'
+ shift, capslock: '\u0626'
+ ctrl, alt, meta: none
+}
+
+key T {
+ label: '\u0641'
+ base: '\u0641'
+ shift, capslock: '\u064F'
+ ctrl, alt, meta: none
+}
+
+key U {
+ label: '\u0639'
+ base: '\u0639'
+ shift, capslock: '\u064E'
+ ctrl, alt, meta: none
+}
+
+key V {
+ label: '\u0631'
+ base: '\u0631'
+ shift, capslock: '\u0670'
+ ctrl, alt, meta: none
+}
+
+key W {
+ label: '\u0635'
+ base: '\u0635'
+ shift, capslock: '\u064C'
+ ctrl, alt, meta: none
+}
+
+key X {
+ label: '\u0637'
+ base: '\u0637'
+ shift, capslock: '\u0653'
+ ctrl, alt, meta: none
+}
+
+key Y {
+ label: '\u063A'
+ base: '\u063A'
+ shift, capslock: '\u0650'
+ ctrl, alt, meta: none
+}
+
+key Z {
+ label: '\u0638'
+ base: '\u0638'
+ shift, capslock: '\u0643'
+ ctrl, alt, meta: none
+}
+
+key 0 {
+ label, number: '\u06F0'
+ base: '\u06F0'
+ shift: '('
+ ctrl, alt, meta: none
+}
+
+key 1 {
+ label, number: '\u06F1'
+ base: '\u06F1'
+ shift: '!'
+ ctrl, alt, meta: none
+}
+
+key 2 {
+ label, number: '\u06F2'
+ base: '\u06F2'
+ shift: '\u066C'
+ ctrl, alt, meta: none
+
+}
+key 3 {
+ label, number: '\u06F3'
+ base: '\u06F3'
+ shift: '\u066B'
+ ctrl, alt, meta: none
+}
+
+key 4 {
+ label, number: '\u06F4'
+ base: '\u06F4'
+ shift: '\uFDFC'
+ ctrl, alt, meta: none
+}
+
+key 5 {
+ label, number: '\u06F5'
+ base: '\u06F5'
+ shift: '\u066A'
+ ctrl, alt, meta: none
+}
+
+key 6 {
+ label, number: '\u06F6'
+ base: '\u06F6'
+ shift: '\u00D7'
+ ctrl, alt, meta: none
+}
+
+
+key 7 {
+ label, number: '\u06F7'
+ base: '\u06F7'
+ shift: '\u060C'
+ ctrl, alt, meta: none
+}
+
+key 8 {
+ label, number: '\u06F8'
+ base: '\u06F8'
+ shift: '*'
+ ctrl, alt, meta: none
+}
+
+key 9 {
+ label, number: '\u06F9'
+ base: '\u06F9'
+ shift: ')'
+ ctrl, alt, meta: none
+}
+
+key SPACE {
+ label: ' '
+ base: ' '
+ ctrl, alt, meta: none
+}
+
+key ENTER {
+ label: '\n'
+ base: '\n'
+ ctrl, alt, meta: none
+}
+
+key TAB {
+ label: '\t'
+ base: '\t'
+ ctrl, alt, meta: none
+}
+
+key COMMA {
+ label, number: '\u0648'
+ base: '\u0648'
+ shift: '<'
+ ctrl, alt, meta: none
+}
+
+key PERIOD {
+ label, number: '.'
+ base: '.'
+ shift: '>'
+ ctrl, alt, meta: none
+}
+
+key SLASH {
+ label, number: '/'
+ base: '/'
+ shift: '\u061F'
+ ctrl, alt, meta: none
+}
+
+key GRAVE {
+ label, number: '`'
+ base: '`'
+ shift: '\u00F7'
+ ctrl, alt, meta: none
+}
+
+
+key MINUS {
+ label, number: '-'
+ base: '-'
+ shift: '_'
+ ctrl, alt, meta: none
+}
+
+key EQUALS {
+ label, number: '='
+ base: '='
+ shift: '+'
+ ctrl, alt, meta: none
+}
+
+key LEFT_BRACKET {
+ label, number: '\u062C'
+ base: '\u062C'
+ shift: '}'
+ ctrl, alt, meta: none
+}
+
+key RIGHT_BRACKET {
+ label, number: '\u0686'
+ base: '\u0686'
+ shift: '{'
+ ctrl, alt, meta: none
+}
+
+key BACKSLASH {
+ label, number: '\\'
+ base: '\\'
+ shift: '|'
+ ctrl, alt, meta: none
+}
+
+key SEMICOLON {
+ label, number: '\u06A9'
+ base: '\u06A9'
+ shift: ':'
+ ctrl, alt, meta: none
+}
+
+key APOSTROPHE {
+ label, number: '\''
+ base: '\''
+ shift: '\"'
+ ctrl, alt, meta: none
+}
+
+### Numeric keypad ###
+
+key NUMPAD_0 {
+ label, number: '0'
+ base: fallback INSERT
+ numlock: '0'
+ ctrl, alt, meta: none
+}
+
+key NUMPAD_1 {
+ label, number: '1'
+ base: fallback MOVE_END
+ numlock: '1'
+ ctrl, alt, meta: none
+}
+
+key NUMPAD_2 {
+ label, number: '2'
+ base: fallback DPAD_DOWN
+ numlock: '2'
+ ctrl, alt, meta: none
+}
+
+key NUMPAD_3 {
+ label, number: '3'
+ base: fallback PAGE_DOWN
+ numlock: '3'
+ ctrl, alt, meta: none
+}
+
+key NUMPAD_4 {
+ label, number: '4'
+ base: fallback DPAD_LEFT
+ numlock: '4'
+ ctrl, alt, meta: none
+}
+
+key NUMPAD_5 {
+ label, number: '5'
+ base: fallback DPAD_CENTER
+ numlock: '5'
+ ctrl, alt, meta: none
+}
+
+key NUMPAD_6 {
+ label, number: '6'
+ base: fallback DPAD_RIGHT
+ numlock: '6'
+ ctrl, alt, meta: none
+}
+
+key NUMPAD_7 {
+ label, number: '7'
+ base: fallback MOVE_HOME
+ numlock: '7'
+ ctrl, alt, meta: none
+}
+
+key NUMPAD_8 {
+ label, number: '8'
+ base: fallback DPAD_UP
+ numlock: '8'
+ ctrl, alt, meta: none
+}
+
+key NUMPAD_9 {
+ label, number: '9'
+ base: fallback PAGE_UP
+ numlock: '9'
+ ctrl, alt, meta: none
+}
+
+key NUMPAD_LEFT_PAREN {
+ label, number: '('
+ base: '('
+ ctrl, alt, meta: none
+}
+
+key NUMPAD_RIGHT_PAREN {
+ label, number: ')'
+ base: ')'
+ ctrl, alt, meta: none
+}
+
+key NUMPAD_DIVIDE {
+ label, number: '/'
+ base: '/'
+ ctrl, alt, meta: none
+}
+
+key NUMPAD_MULTIPLY {
+ label, number: '*'
+ base: '*'
+ ctrl, alt, meta: none
+}
+
+key NUMPAD_SUBTRACT {
+ label, number: '-'
+ base: '-'
+ ctrl, alt, meta: none
+}
+
+key NUMPAD_ADD {
+ label, number: '+'
+ base: '+'
+ ctrl, alt, meta: none
+}
+
+key NUMPAD_DOT {
+ label, number: '.'
+ base: fallback FORWARD_DEL
+ numlock: '.'
+ ctrl, alt, meta: none
+}
+
+key NUMPAD_COMMA {
+ label, number: ','
+ base: ','
+ ctrl, alt, meta: none
+}
+
+key NUMPAD_EQUALS {
+ label, number: '='
+ base: '='
+ ctrl, alt, meta: none
+}
+
+key NUMPAD_ENTER {
+ label: '\n'
+ base: '\n' fallback ENTER
+ ctrl, alt, meta: none fallback ENTER
+}
diff --git a/packages/InputDevices/res/values/strings.xml b/packages/InputDevices/res/values/strings.xml
index 5644c9a..1e26226 100644
--- a/packages/InputDevices/res/values/strings.xml
+++ b/packages/InputDevices/res/values/strings.xml
@@ -119,4 +119,7 @@
<!-- Latvian keyboard layout label. [CHAR LIMIT=35] -->
<string name="keyboard_layout_latvian">Latvian</string>
+
+ <!-- Persian keyboard layout label. [CHAR LIMIT=35] -->
+ <string name="keyboard_layout_persian">Persian</string>
</resources>
diff --git a/packages/InputDevices/res/xml/keyboard_layouts.xml b/packages/InputDevices/res/xml/keyboard_layouts.xml
index a302162..c55711a 100644
--- a/packages/InputDevices/res/xml/keyboard_layouts.xml
+++ b/packages/InputDevices/res/xml/keyboard_layouts.xml
@@ -151,4 +151,8 @@
<keyboard-layout android:name="keyboard_layout_latvian"
android:label="@string/keyboard_layout_latvian"
android:keyboardLayout="@raw/keyboard_layout_latvian_qwerty" />
+
+ <keyboard-layout android:name="keyboard_layout_persian"
+ android:label="@string/keyboard_layout_persian"
+ android:keyboardLayout="@raw/keyboard_layout_persian" />
</keyboard-layouts>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 24f6c13..c997160 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -108,6 +108,7 @@
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
<!-- Keyguard -->
+ <uses-permission android:name="com.android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS" />
<uses-permission android:name="android.permission.CONTROL_KEYGUARD" />
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginActivity.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginActivity.java
deleted file mode 100644
index 925214e..0000000
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginActivity.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.systemui.plugins;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.res.Resources;
-import android.os.Bundle;
-
-import com.android.systemui.plugins.annotations.ProvidesInterface;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * A PluginActivity is an activity that replaces another full activity (e.g. RecentsActivity)
- * at runtime within the sysui process.
- */
-@ProvidesInterface(version = PluginActivity.VERSION)
-public abstract class PluginActivity extends Activity implements Plugin {
-
- public static final int VERSION = 1;
-
- public static final String ACTION_RECENTS = "com.android.systemui.action.PLUGIN_RECENTS";
-
- private Context mSysuiContext;
- private boolean mSettingActionBar;
-
- @Override
- public final void onCreate(Context sysuiContext, Context pluginContext) {
- mSysuiContext = sysuiContext;
- super.attachBaseContext(pluginContext);
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- Theme theme = getClass().getDeclaredAnnotation(Theme.class);
- if (theme != null && theme.value() != 0) {
- setTheme(theme.value());
- }
- mSettingActionBar = true;
- getActionBar();
- mSettingActionBar = false;
- }
-
- @Override
- public Resources getResources() {
- return mSettingActionBar ? mSysuiContext.getResources() : super.getResources();
- }
-
- @Override
- protected void attachBaseContext(Context newBase) {
- mSysuiContext = newBase;
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- }
-
- public Context getSysuiContext() {
- return mSysuiContext;
- }
-
- public Context getPluginContext() {
- return getBaseContext();
- }
-
- /**
- * Since PluginActivities are declared as services instead of activities (since they
- * are plugins), they can't have a theme attached to them. Instead a PluginActivity
- * can annotate itself with @Theme to specify the resource of the style it wants
- * to be themed with.
- */
- @Retention(RetentionPolicy.RUNTIME)
- public @interface Theme {
- int value();
- }
-}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginDependency.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginDependency.java
index db2e376..25ce3dd 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginDependency.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginDependency.java
@@ -21,11 +21,6 @@
public static final int VERSION = 1;
static DependencyProvider sProvider;
- /**
- * Allows a plugin to get a hold of static dependencies if they have declared dependence
- * on their interface. For one-shot plugins this will only work during onCreate and will
- * not work afterwards.
- */
public static <T> T get(Plugin p, Class<T> cls) {
return sProvider.get(p, cls);
}
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_esim_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_esim_area.xml
index 8cbd94b..db508c9 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_esim_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_esim_area.xml
@@ -25,8 +25,7 @@
android:id="@+id/keyguard_disable_esim"
android:visibility="gone"
android:text="@string/disable_carrier_button_text"
- style="?android:attr/buttonBarButtonStyle"
+ style="@style/Keyguard.TextView"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textSize="@dimen/kg_status_line_font_size"
- android:textColor="?android:attr/textColorSecondary"
android:textAllCaps="@bool/kg_use_all_caps" />
diff --git a/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml b/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml
index bc29012..dde2db2 100644
--- a/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml
+++ b/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml
@@ -20,10 +20,7 @@
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginLeft="@dimen/car_fullscreen_user_pod_margin_side"
- android:layout_marginRight="@dimen/car_fullscreen_user_pod_margin_side"
- android:gravity="center"
- android:layout_weight="1" >
+ android:gravity="center" >
<ImageView android:id="@+id/user_avatar"
android:layout_gravity="center"
@@ -31,10 +28,13 @@
android:layout_height="@dimen/car_fullscreen_user_pod_image_avatar_height" />
<TextView android:id="@+id/user_name"
- android:layout_width="wrap_content"
+ android:layout_width="@dimen/car_fullscreen_user_pod_width"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/car_fullscreen_user_pod_margin_above_text"
android:textSize="@dimen/car_fullscreen_user_pod_text_size"
android:textColor="@color/qs_user_detail_name"
+ android:ellipsize="end"
+ android:singleLine="true"
+ android:gravity="center_horizontal"
android:layout_gravity="center_horizontal" />
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/car_fullscreen_user_pod_container.xml b/packages/SystemUI/res/layout/car_fullscreen_user_pod_container.xml
index 8c55680..99d010f 100644
--- a/packages/SystemUI/res/layout/car_fullscreen_user_pod_container.xml
+++ b/packages/SystemUI/res/layout/car_fullscreen_user_pod_container.xml
@@ -18,7 +18,8 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_gravity="center">
+ android:gravity="center"
+ android:layout_gravity="center" >
<!-- car_fullscreen_user_pods will be dynamically added here. -->
</LinearLayout>
diff --git a/packages/SystemUI/res/values/dimens_car.xml b/packages/SystemUI/res/values/dimens_car.xml
index 89078f5..5f56c4e 100644
--- a/packages/SystemUI/res/values/dimens_car.xml
+++ b/packages/SystemUI/res/values/dimens_car.xml
@@ -18,11 +18,12 @@
<resources>
<dimen name="car_margin">148dp</dimen>
- <dimen name="car_fullscreen_user_pod_margin_side">44dp</dimen>
<dimen name="car_fullscreen_user_pod_margin_above_text">24dp</dimen>
+ <dimen name="car_fullscreen_user_pod_margin_between">24dp</dimen>
<dimen name="car_fullscreen_user_pod_icon_text_size">96dp</dimen>
<dimen name="car_fullscreen_user_pod_image_avatar_width">192dp</dimen>
<dimen name="car_fullscreen_user_pod_image_avatar_height">192dp</dimen>
+ <dimen name="car_fullscreen_user_pod_width">264dp</dimen>
<dimen name="car_fullscreen_user_pod_text_size">40sp</dimen> <!-- B1 -->
<dimen name="car_navigation_button_width">64dp</dimen>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardEsimArea.java b/packages/SystemUI/src/com/android/keyguard/KeyguardEsimArea.java
index ce3068d..cb5afec 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardEsimArea.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardEsimArea.java
@@ -72,6 +72,7 @@
public KeyguardEsimArea(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
+ mEuiccManager = (EuiccManager) context.getSystemService(Context.EUICC_SERVICE);
setOnClickListener(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index ecc2111..49253ec 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -34,7 +34,6 @@
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.PluginActivityManager;
import com.android.systemui.plugins.PluginDependencyProvider;
import com.android.systemui.plugins.PluginManager;
import com.android.systemui.plugins.PluginManagerImpl;
@@ -295,8 +294,6 @@
mProviders.put(UiOffloadThread.class, UiOffloadThread::new);
- mProviders.put(PluginActivityManager.class,
- () -> new PluginActivityManager(mContext, getDependency(PluginManager.class)));
mProviders.put(PowerUI.WarningsUI.class, () -> new PowerNotificationWarnings(mContext));
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 49a076f..9adafda 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -16,7 +16,6 @@
package com.android.systemui;
-import android.app.Activity;
import android.app.ActivityThread;
import android.app.Application;
import android.content.BroadcastReceiver;
@@ -41,7 +40,6 @@
import com.android.systemui.plugins.GlobalActions;
import com.android.systemui.plugins.OverlayPlugin;
import com.android.systemui.plugins.Plugin;
-import com.android.systemui.plugins.PluginActivityManager;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.PluginManager;
import com.android.systemui.power.PowerUI;
@@ -281,10 +279,4 @@
public SystemUI[] getServices() {
return mServices;
}
-
- @Override
- public Activity instantiateActivity(ClassLoader cl, String className, Intent intent) {
- if (!mServicesStarted) return null;
- return Dependency.get(PluginActivityManager.class).instantiate(cl, className, intent);
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginActivityManager.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginActivityManager.java
deleted file mode 100644
index 9becc38..0000000
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginActivityManager.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.systemui.plugins;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-
-public class PluginActivityManager {
-
- private final Context mContext;
- private final PluginManager mPluginManager;
- private final ArrayMap<String, String> mActionLookup = new ArrayMap<>();
-
- public PluginActivityManager(Context context, PluginManager pluginManager) {
- mContext = context;
- mPluginManager = pluginManager;
- }
-
- public void addActivityPlugin(String className, String action) {
- mActionLookup.put(className, action);
- }
-
- public Activity instantiate(ClassLoader cl, String className, Intent intent) {
- String action = mActionLookup.get(className);
- if (TextUtils.isEmpty(action)) return null;
- return mPluginManager.getOneShotPlugin(action, PluginActivity.class);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
index a968399..493d244 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
@@ -42,6 +42,7 @@
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.systemui.Dependency;
import com.android.systemui.plugins.PluginInstanceManager.PluginContextWrapper;
+import com.android.systemui.plugins.PluginInstanceManager.PluginInfo;
import com.android.systemui.plugins.annotations.ProvidesInterface;
import dalvik.system.PathClassLoader;
@@ -119,21 +120,14 @@
}
PluginInstanceManager<T> p = mFactory.createPluginInstanceManager(mContext, action, null,
false, mLooper, cls, this);
- PluginListener<Plugin> listener = new PluginListener<Plugin>() {
- @Override
- public void onPluginConnected(Plugin plugin, Context pluginContext) { }
- };
- mPluginMap.put(listener, p);
mPluginPrefs.addAction(action);
- PluginInstanceManager.PluginInfo<T> info = p.getPlugin();
+ PluginInfo<T> info = p.getPlugin();
if (info != null) {
mOneShotPackages.add(info.mPackage);
mHasOneShot = true;
startListening();
- mPluginMap.remove(listener);
return info.mPlugin;
}
- mPluginMap.remove(listener);
return null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
index e574c01..a48bcbd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
@@ -310,11 +310,47 @@
vpnWarning.setMovementMethod(new LinkMovementMethod());
}
+ // Note: if a new section is added, should update configSubtitleVisibility to include
+ // the handling of the subtitle
+ configSubtitleVisibility(managementMessage != null,
+ caCertsMessage != null,
+ networkLoggingMessage != null,
+ vpnMessage != null,
+ dialogView);
+
mDialog.show();
mDialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
+ protected void configSubtitleVisibility(boolean showDeviceManagement, boolean showCaCerts,
+ boolean showNetworkLogging, boolean showVpn, View dialogView) {
+ // Device Management title should always been shown
+ // When there is a Device Management message, all subtitles should be shown
+ if (showDeviceManagement) {
+ return;
+ }
+ // Hide the subtitle if there is only 1 message shown
+ int mSectionCountExcludingDeviceMgt = 0;
+ if (showCaCerts) { mSectionCountExcludingDeviceMgt++; }
+ if (showNetworkLogging) { mSectionCountExcludingDeviceMgt++; }
+ if (showVpn) { mSectionCountExcludingDeviceMgt++; }
+
+ // No work needed if there is no sections or more than 1 section
+ if (mSectionCountExcludingDeviceMgt != 1) {
+ return;
+ }
+ if (showCaCerts) {
+ dialogView.findViewById(R.id.ca_certs_subtitle).setVisibility(View.GONE);
+ }
+ if (showNetworkLogging) {
+ dialogView.findViewById(R.id.network_logging_subtitle).setVisibility(View.GONE);
+ }
+ if (showVpn) {
+ dialogView.findViewById(R.id.vpn_subtitle).setVisibility(View.GONE);
+ }
+ }
+
private String getSettingsButton() {
return mContext.getString(R.string.monitoring_button_view_policies);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index d10e080..4a8b43e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -43,14 +43,11 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.Dependency;
import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.SystemUI;
-import com.android.systemui.plugins.PluginActivity;
-import com.android.systemui.plugins.PluginActivityManager;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
import com.android.systemui.recents.events.activity.DockedTopTaskEvent;
@@ -239,8 +236,6 @@
registerWithSystemUser();
}
putComponent(Recents.class, this);
- Dependency.get(PluginActivityManager.class).addActivityPlugin(RecentsImpl.RECENTS_ACTIVITY,
- PluginActivity.ACTION_RECENTS);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java
index b22a2c1..f178aa6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.car;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -100,7 +101,9 @@
*/
private final class Adapter extends PagerAdapter implements View.OnLayoutChangeListener {
private final int mPodWidth;
- private final int mPodMargin;
+ private final int mPodMarginBetween;
+ private final int mPodImageAvatarWidth;
+ private final int mPodImageAvatarHeight;
private final WrappedBaseUserAdapter mUserAdapter;
private int mContainerWidth;
@@ -108,10 +111,15 @@
public Adapter(UserSwitcherController controller) {
super();
mUserAdapter = new WrappedBaseUserAdapter(controller, this);
- mPodWidth = getResources().getDimensionPixelSize(
+
+ Resources res = getResources();
+ mPodWidth = res.getDimensionPixelSize(R.dimen.car_fullscreen_user_pod_width);
+ mPodMarginBetween = res.getDimensionPixelSize(
+ R.dimen.car_fullscreen_user_pod_margin_between);
+ mPodImageAvatarWidth = res.getDimensionPixelSize(
R.dimen.car_fullscreen_user_pod_image_avatar_width);
- mPodMargin = getResources().getDimensionPixelSize(
- R.dimen.car_fullscreen_user_pod_margin_side);
+ mPodImageAvatarHeight = res.getDimensionPixelSize(
+ R.dimen.car_fullscreen_user_pod_image_avatar_height);
}
@Override
@@ -121,9 +129,12 @@
private int getIconsPerPage() {
// We need to know how many pods we need in this page. Each pod has its own width and
- // margins on both sides. We can then divide the measured width of the parent by the
+ // a margin between them. We can then divide the measured width of the parent by the
// sum of pod width and margin to get the number of pods that will completely fit.
- return mContainerWidth / (mPodWidth + mPodMargin * 2);
+ // There is one less margin than the number of pods (eg. for 5 pods, there are 4
+ // margins), so need to add the margin to the measured width to account for that.
+ return (mContainerWidth + mPodMarginBetween) /
+ (mPodWidth + mPodMarginBetween);
}
@Override
@@ -137,7 +148,17 @@
int iconsPerPage = getIconsPerPage();
int limit = Math.min(mUserAdapter.getCount(), (position + 1) * iconsPerPage);
for (int i = position * iconsPerPage; i < limit; i++) {
- pods.addView(makeUserPod(inflater, context, i, pods));
+ View v = makeUserPod(inflater, context, i, pods);
+ pods.addView(v);
+ // This is hacky, but the dividers on the pod container LinearLayout don't seem
+ // to work for whatever reason. Instead, set a right margin on the pod if it's not
+ // the right-most pod and there is more than one pod in the container.
+ if (i < limit - 1 && limit > 1) {
+ LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
+ LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+ params.setMargins(0, 0, mPodMarginBetween, 0);
+ v.setLayoutParams(params);
+ }
}
container.addView(pods);
return pods;
@@ -151,7 +172,8 @@
*/
private Bitmap getDefaultUserIcon(CharSequence userName) {
CharSequence displayText = userName.subSequence(0, 1);
- Bitmap out = Bitmap.createBitmap(mPodWidth, mPodWidth, Bitmap.Config.ARGB_8888);
+ Bitmap out = Bitmap.createBitmap(mPodImageAvatarWidth, mPodImageAvatarHeight,
+ Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(out);
// Draw the circle background.
@@ -159,7 +181,7 @@
shape.setShape(GradientDrawable.RADIAL_GRADIENT);
shape.setGradientRadius(1.0f);
shape.setColor(getContext().getColor(R.color.car_user_switcher_no_user_image_bgcolor));
- shape.setBounds(0, 0, mPodWidth, mPodWidth);
+ shape.setBounds(0, 0, mPodImageAvatarWidth, mPodImageAvatarHeight);
shape.draw(canvas);
// Draw the letter in the center.
@@ -174,8 +196,8 @@
// correct this, half the difference between the top and bottom distance metrics of the
// font gives the offset of the font. Bottom is a positive value, top is negative, so
// the different is actually a sum. The "half" operation is then factored out.
- canvas.drawText(displayText.toString(),
- mPodWidth / 2, (mPodWidth - (metrics.bottom + metrics.top)) / 2, paint);
+ canvas.drawText(displayText.toString(), mPodImageAvatarWidth / 2,
+ (mPodImageAvatarHeight - (metrics.bottom + metrics.top)) / 2, paint);
return out;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index c45c05e..f06dd7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -54,6 +54,7 @@
private boolean mFullyPulsing;
private float mAodFrontScrimOpacity = 0;
+ private Runnable mSetDozeInFrontAlphaDelayed;
public DozeScrimController(ScrimController scrimController, Context context) {
mContext = context;
@@ -69,8 +70,7 @@
mDozingAborted = false;
abortAnimations();
mScrimController.setDozeBehindAlpha(1f);
- mScrimController.setDozeInFrontAlpha(
- mDozeParameters.getAlwaysOn() ? mAodFrontScrimOpacity : 1f);
+ setDozeInFrontAlpha(mDozeParameters.getAlwaysOn() ? mAodFrontScrimOpacity : 1f);
} else {
cancelPulsing();
if (animate) {
@@ -83,7 +83,7 @@
} else {
abortAnimations();
mScrimController.setDozeBehindAlpha(0f);
- mScrimController.setDozeInFrontAlpha(0f);
+ setDozeInFrontAlpha(0f);
}
}
}
@@ -97,7 +97,7 @@
mAodFrontScrimOpacity = scrimOpacity;
if (mDozing && !isPulsing() && !mDozingAborted && !mWakeAndUnlocking
&& mDozeParameters.getAlwaysOn()) {
- mScrimController.setDozeInFrontAlpha(mAodFrontScrimOpacity);
+ setDozeInFrontAlpha(mAodFrontScrimOpacity);
}
}
@@ -107,7 +107,7 @@
if (!mWakeAndUnlocking) {
mWakeAndUnlocking = true;
mScrimController.setDozeBehindAlpha(0f);
- mScrimController.setDozeInFrontAlpha(0f);
+ setDozeInFrontAlpha(0f);
}
}
@@ -127,7 +127,7 @@
// be invoked when we're done so that the caller can drop the pulse wakelock.
mPulseCallback = callback;
mPulseReason = reason;
- mScrimController.setDozeInFrontAlpha(1f);
+ setDozeInFrontAlpha(1f);
mHandler.post(mPulseIn);
}
@@ -138,9 +138,8 @@
cancelPulsing();
if (mDozing && !mWakeAndUnlocking) {
mScrimController.setDozeBehindAlpha(1f);
- mScrimController.setDozeInFrontAlpha(
- mDozeParameters.getAlwaysOn() && !mDozingAborted ?
- mAodFrontScrimOpacity : 1f);
+ setDozeInFrontAlpha(mDozeParameters.getAlwaysOn() && !mDozingAborted
+ ? mAodFrontScrimOpacity : 1f);
}
}
@@ -295,6 +294,25 @@
: mScrimController.getDozeBehindAlpha();
}
+ private void setDozeInFrontAlpha(float opacity) {
+ setDozeInFrontAlphaDelayed(opacity, 0 /* delay */);
+
+ }
+
+ private void setDozeInFrontAlphaDelayed(float opacity, long delayMs) {
+ if (mSetDozeInFrontAlphaDelayed != null) {
+ mHandler.removeCallbacks(mSetDozeInFrontAlphaDelayed);
+ mSetDozeInFrontAlphaDelayed = null;
+ }
+ if (delayMs < 0) {
+ mScrimController.setDozeInFrontAlpha(opacity);
+ } else {
+ mHandler.postDelayed(mSetDozeInFrontAlphaDelayed = () -> {
+ setDozeInFrontAlpha(opacity);
+ }, delayMs);
+ }
+ }
+
private final Runnable mPulseIn = new Runnable() {
@Override
public void run() {
@@ -364,7 +382,9 @@
// Signal that the pulse is all finished so we can turn the screen off now.
DozeScrimController.this.pulseFinished();
if (mDozeParameters.getAlwaysOn()) {
- mScrimController.setDozeInFrontAlpha(mAodFrontScrimOpacity);
+ // Setting power states can happen after we push out the frame. Make sure we
+ // stay fully opaque until the power state request reaches the lower levels.
+ setDozeInFrontAlphaDelayed(mAodFrontScrimOpacity, 30);
}
}
};
diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
index bba982c..b8e9fcd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
@@ -26,6 +26,8 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -34,10 +36,11 @@
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.systemui.Dependency;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.plugins.PluginInstanceManager.PluginInfo;
import com.android.systemui.plugins.annotations.ProvidesInterface;
+import com.android.systemui.plugins.PluginInstanceManager.PluginInfo;
import com.android.systemui.plugins.PluginManagerImpl.PluginInstanceManagerFactory;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
index a8487b3..4f98836 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
@@ -29,6 +29,7 @@
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
import android.text.SpannableStringBuilder;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
@@ -395,6 +396,57 @@
mFooter.getVpnMessage(false, true, VPN_PACKAGE, null));
}
+ @Test
+ public void testConfigSubtitleVisibility() {
+ View view = LayoutInflater.from(mContext)
+ .inflate(R.layout.quick_settings_footer_dialog, null);
+
+ // Device Management subtitle should be shown when there is Device Management section only
+ // Other sections visibility will be set somewhere else so it will not be tested here
+ mFooter.configSubtitleVisibility(true, false, false, false, view);
+ assertEquals(View.VISIBLE,
+ view.findViewById(R.id.device_management_subtitle).getVisibility());
+
+ // If there are multiple sections, all subtitles should be shown
+ mFooter.configSubtitleVisibility(true, true, false, false, view);
+ assertEquals(View.VISIBLE,
+ view.findViewById(R.id.device_management_subtitle).getVisibility());
+ assertEquals(View.VISIBLE,
+ view.findViewById(R.id.ca_certs_subtitle).getVisibility());
+
+ // If there are multiple sections, all subtitles should be shown
+ mFooter.configSubtitleVisibility(true, true, true, true, view);
+ assertEquals(View.VISIBLE,
+ view.findViewById(R.id.device_management_subtitle).getVisibility());
+ assertEquals(View.VISIBLE,
+ view.findViewById(R.id.ca_certs_subtitle).getVisibility());
+ assertEquals(View.VISIBLE,
+ view.findViewById(R.id.network_logging_subtitle).getVisibility());
+ assertEquals(View.VISIBLE,
+ view.findViewById(R.id.vpn_subtitle).getVisibility());
+
+ // If there are multiple sections, all subtitles should be shown, event if there is no
+ // Device Management section
+ mFooter.configSubtitleVisibility(false, true, true, true, view);
+ assertEquals(View.VISIBLE,
+ view.findViewById(R.id.ca_certs_subtitle).getVisibility());
+ assertEquals(View.VISIBLE,
+ view.findViewById(R.id.network_logging_subtitle).getVisibility());
+ assertEquals(View.VISIBLE,
+ view.findViewById(R.id.vpn_subtitle).getVisibility());
+
+ // If there is only 1 section, the title should be hidden
+ mFooter.configSubtitleVisibility(false, true, false, false, view);
+ assertEquals(View.GONE,
+ view.findViewById(R.id.ca_certs_subtitle).getVisibility());
+ mFooter.configSubtitleVisibility(false, false, true, false, view);
+ assertEquals(View.GONE,
+ view.findViewById(R.id.network_logging_subtitle).getVisibility());
+ mFooter.configSubtitleVisibility(false, false, false, true, view);
+ assertEquals(View.GONE,
+ view.findViewById(R.id.vpn_subtitle).getVisibility());
+ }
+
private CharSequence addLink(CharSequence description) {
final SpannableStringBuilder message = new SpannableStringBuilder();
message.append(description);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakePluginManager.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakePluginManager.java
index d1b1c5b..0a83a89 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakePluginManager.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakePluginManager.java
@@ -14,6 +14,7 @@
package com.android.systemui.utils.leaks;
+import android.content.Context;
import android.testing.LeakCheck;
import com.android.systemui.plugins.Plugin;
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index e854079..71f699c 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -655,19 +655,6 @@
}
@Override
- public void dismissUi() {
- final UserHandle user = getCallingUserHandle();
-
- synchronized (mLock) {
- final AutofillManagerServiceImpl service = peekServiceForUserLocked(
- user.getIdentifier());
- if (service != null) {
- service.dismissUi();
- }
- }
- }
-
- @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 841b1a5..751c054 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -41,6 +41,7 @@
import android.os.Looper;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.service.autofill.AutofillService;
@@ -634,12 +635,6 @@
}
}
- void dismissUi() {
- if (sVerbose) Slog.v(TAG, "dismissUi()");
-
- mUi.hideAll(null);
- }
-
private void sendStateToClients(boolean resetClient) {
final RemoteCallbackList<IAutoFillManagerClient> clients;
final int userClientCount;
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 2a2797c..f8c0e27 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -562,7 +562,10 @@
void onTimeout(RemoteFillService remoteService) {
// NOTE: Must make these 2 calls asynchronously, because the cancellation signal is
// handled by the service, which could block.
- remoteService.dispatchOnFillTimeout(mCancellation);
+ final ICancellationSignal cancellation = mCancellation;
+ if (cancellation != null) {
+ remoteService.dispatchOnFillTimeout(cancellation);
+ }
remoteService.dispatchOnFillRequestFailure(PendingFillRequest.this, null);
}
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index 0351865..3727c6e 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -209,9 +209,6 @@
final View yesButton = view.findViewById(R.id.autofill_save_yes);
yesButton.setOnClickListener((v) -> mListener.onSave());
- final View closeButton = view.findViewById(R.id.autofill_save_close);
- closeButton.setOnClickListener(cancelListener);
-
mDialog = new Dialog(context, R.style.Theme_DeviceDefault_Light_Panel);
mDialog.setContentView(view);
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 3a4c9f8..901e1e7 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -547,6 +547,18 @@
}
}
+ @Override
+ public void tetherLimitReached(ITetheringStatsProvider provider) {
+ mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG);
+ synchronized(mTetheringStatsProviders) {
+ if (!mTetheringStatsProviders.containsKey(provider)) {
+ return;
+ }
+ // No current code examines the interface parameter in a global alert. Just pass null.
+ notifyLimitReached(LIMIT_GLOBAL_ALERT, null);
+ }
+ }
+
// Sync the state of the given chain with the native daemon.
private void syncFirewallChainLocked(int chain, String name) {
SparseIntArray rules;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1d860d6..325ffb4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1346,7 +1346,7 @@
* Set while we are running a voice interaction. This overrides
* sleeping while it is active.
*/
- private IVoiceInteractionSession mRunningVoice;
+ IVoiceInteractionSession mRunningVoice;
/**
* For some direct access we need to power manager.
@@ -1366,13 +1366,6 @@
private int mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
/**
- * A list of tokens that cause the top activity to be put to sleep.
- * They are used by components that may hide and block interaction with underlying
- * activities.
- */
- final ArrayList<SleepToken> mSleepTokens = new ArrayList<SleepToken>();
-
- /**
* Set if we are shutting down the system, similar to sleeping.
*/
boolean mShuttingDown = false;
@@ -12390,7 +12383,19 @@
void onWakefulnessChanged(int wakefulness) {
synchronized(this) {
mWakefulness = wakefulness;
- updateSleepIfNeededLocked();
+
+ // Also update state in a special way for running foreground services UI.
+ switch (mWakefulness) {
+ case PowerManagerInternal.WAKEFULNESS_ASLEEP:
+ case PowerManagerInternal.WAKEFULNESS_DREAMING:
+ case PowerManagerInternal.WAKEFULNESS_DOZING:
+ mServices.updateScreenStateLocked(false /* screenOn */);
+ break;
+ case PowerManagerInternal.WAKEFULNESS_AWAKE:
+ default:
+ mServices.updateScreenStateLocked(true /* screenOn */);
+ break;
+ }
}
}
@@ -12410,14 +12415,24 @@
}
void updateSleepIfNeededLocked() {
- final boolean shouldSleep = shouldSleepLocked();
- if (mSleeping && !shouldSleep) {
- mSleeping = false;
- startTimeTrackingFocusedActivityLocked();
- mTopProcessState = ActivityManager.PROCESS_STATE_TOP;
- mStackSupervisor.comeOutOfSleepIfNeededLocked();
- sendNotifyVrManagerOfSleepState(false);
- updateOomAdjLocked();
+ final boolean shouldSleep = !mStackSupervisor.hasAwakeDisplay();
+ final boolean wasSleeping = mSleeping;
+
+ if (!shouldSleep) {
+ // If wasSleeping is true, we need to wake up activity manager state from when
+ // we started sleeping. In either case, we need to apply the sleep tokens, which
+ // will wake up stacks or put them to sleep as appropriate.
+ if (wasSleeping) {
+ mSleeping = false;
+ startTimeTrackingFocusedActivityLocked();
+ mTopProcessState = ActivityManager.PROCESS_STATE_TOP;
+ mStackSupervisor.comeOutOfSleepIfNeededLocked();
+ }
+ mStackSupervisor.applySleepTokensLocked(true /* applyToStacks */);
+ if (wasSleeping) {
+ sendNotifyVrManagerOfSleepState(false);
+ updateOomAdjLocked();
+ }
} else if (!mSleeping && shouldSleep) {
mSleeping = true;
if (mCurAppTimeTracker != null) {
@@ -12428,40 +12443,6 @@
sendNotifyVrManagerOfSleepState(true);
updateOomAdjLocked();
}
-
- // Also update state in a special way for running foreground services UI.
- switch (mWakefulness) {
- case PowerManagerInternal.WAKEFULNESS_ASLEEP:
- case PowerManagerInternal.WAKEFULNESS_DREAMING:
- case PowerManagerInternal.WAKEFULNESS_DOZING:
- mServices.updateScreenStateLocked(false);
- break;
- case PowerManagerInternal.WAKEFULNESS_AWAKE:
- default:
- mServices.updateScreenStateLocked(true);
- break;
- }
- }
-
- private boolean shouldSleepLocked() {
- // Resume applications while running a voice interactor.
- if (mRunningVoice != null) {
- return false;
- }
-
- // TODO: Transform the lock screen state into a sleep token instead.
- switch (mWakefulness) {
- case PowerManagerInternal.WAKEFULNESS_AWAKE:
- case PowerManagerInternal.WAKEFULNESS_DREAMING:
- // Pause applications whenever the lock screen is shown or any sleep
- // tokens have been acquired.
- return mKeyguardController.isKeyguardShowing() || !mSleepTokens.isEmpty();
- case PowerManagerInternal.WAKEFULNESS_DOZING:
- case PowerManagerInternal.WAKEFULNESS_ASLEEP:
- default:
- // If we're asleep then pause applications unconditionally.
- return true;
- }
}
/** Pokes the task persister. */
@@ -12502,6 +12483,7 @@
synchronized(this) {
mShuttingDown = true;
+ mStackSupervisor.prepareForShutdownLocked();
updateEventDispatchingLocked();
timedout = mStackSupervisor.shutdownLocked(timeout);
}
@@ -14916,6 +14898,14 @@
this, in, out, err, args, callback, resultReceiver);
}
+ SleepToken acquireSleepToken(String tag, int displayId) {
+ synchronized (this) {
+ final SleepToken token = mStackSupervisor.createSleepTokenLocked(tag, displayId);
+ updateSleepIfNeededLocked();
+ return token;
+ }
+ }
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
@@ -15812,7 +15802,7 @@
if (dumpPackage == null) {
pw.println(" mWakefulness="
+ PowerManagerInternal.wakefulnessToString(mWakefulness));
- pw.println(" mSleepTokens=" + mSleepTokens);
+ pw.println(" mSleepTokens=" + mStackSupervisor.mSleepTokens);
pw.println(" mSleeping=" + mSleeping);
pw.println(" mShuttingDown=" + mShuttingDown + " mTestPssMode=" + mTestPssMode);
if (mRunningVoice != null) {
@@ -23772,15 +23762,9 @@
}
@Override
- public SleepToken acquireSleepToken(String tag) {
+ public SleepToken acquireSleepToken(String tag, int displayId) {
Preconditions.checkNotNull(tag);
-
- synchronized (ActivityManagerService.this) {
- SleepTokenImpl token = new SleepTokenImpl(tag);
- mSleepTokens.add(token);
- updateSleepIfNeededLocked();
- return token;
- }
+ return ActivityManagerService.this.acquireSleepToken(tag, displayId);
}
@Override
@@ -24217,30 +24201,6 @@
}
}
- private final class SleepTokenImpl extends SleepToken {
- private final String mTag;
- private final long mAcquireTime;
-
- public SleepTokenImpl(String tag) {
- mTag = tag;
- mAcquireTime = SystemClock.uptimeMillis();
- }
-
- @Override
- public void release() {
- synchronized (ActivityManagerService.this) {
- if (mSleepTokens.remove(this)) {
- updateSleepIfNeededLocked();
- }
- }
- }
-
- @Override
- public String toString() {
- return "{\"" + mTag + "\", acquire at " + TimeUtils.formatUptime(mAcquireTime) + "}";
- }
- }
-
/**
* An implementation of IAppTask, that allows an app to manage its own tasks via
* {@link android.app.ActivityManager.AppTask}. We keep track of the callingUid to ensure that
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 8cab918..6b1f758 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -1341,7 +1341,9 @@
intent, getUriPermissionsLocked(), userId);
final ReferrerIntent rintent = new ReferrerIntent(intent, referrer);
boolean unsent = true;
- final boolean isTopActivityWhileSleeping = service.isSleepingLocked() && isTopRunningActivity();
+ final ActivityStack stack = getStack();
+ final boolean isTopActivityWhileSleeping = isTopRunningActivity()
+ && (stack != null ? stack.shouldSleepActivities() : service.isSleepingLocked());
// We want to immediately deliver the intent to the activity if:
// - It is currently resumed or paused. i.e. it is currently visible to the user and we want
@@ -1731,7 +1733,7 @@
// If the screen is going to turn on because the caller explicitly requested it and
// the keyguard is not showing don't attempt to sleep. Otherwise the Activity will
// pause and then resume again later, which will result in a double life-cycle event.
- mStackSupervisor.checkReadyForSleepLocked();
+ stack.checkReadyForSleep();
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 896f846..84fd0de 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1170,10 +1170,25 @@
}
}
+ void checkReadyForSleep() {
+ if (shouldSleepActivities() && goToSleepIfPossible(false /* shuttingDown */)) {
+ mStackSupervisor.checkReadyForSleepLocked(true /* allowDelay */);
+ }
+ }
+
/**
+ * Tries to put the activities in the stack to sleep.
+ *
+ * If the stack is not in a state where its activities can be put to sleep, this function will
+ * start any necessary actions to move the stack into such a state. It is expected that this
+ * function get called again when those actions complete.
+ *
+ * @param shuttingDown true when the called because the device is shutting down.
* @return true if something must be done before going to sleep.
*/
- boolean checkReadyForSleepLocked() {
+ boolean goToSleepIfPossible(boolean shuttingDown) {
+ boolean shouldSleep = true;
+
if (mResumedActivity != null) {
// Still have something resumed; can't sleep until it is paused.
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep needs to pause " + mResumedActivity);
@@ -1183,26 +1198,47 @@
// If we are in the middle of resuming the top activity in
// {@link #resumeTopActivityUncheckedLocked}, mResumedActivity will be set but not
// resumed yet. We must not proceed pausing the activity here. This method will be
- // called again if necessary as part of
+ // called again if necessary as part of {@link #checkReadyForSleep} or
// {@link ActivityStackSupervisor#checkReadyForSleepLocked}.
if (mStackSupervisor.inResumeTopActivity) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "In the middle of resuming top activity "
+ mResumedActivity);
- return true;
+ } else {
+ startPausingLocked(false, true, null, false);
}
-
- startPausingLocked(false, true, null, false);
- return true;
- }
- if (mPausingActivity != null) {
+ shouldSleep = false ;
+ } else if (mPausingActivity != null) {
// Still waiting for something to pause; can't sleep yet.
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still waiting to pause " + mPausingActivity);
- return true;
+ shouldSleep = false;
}
- return false;
+
+ if (!shuttingDown) {
+ if (containsActivityFromStack(mStackSupervisor.mStoppingActivities)) {
+ // Still need to tell some activities to stop; can't sleep yet.
+ if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still need to stop "
+ + mStackSupervisor.mStoppingActivities.size() + " activities");
+
+ mStackSupervisor.scheduleIdleLocked();
+ shouldSleep = false;
+ }
+
+ if (containsActivityFromStack(mStackSupervisor.mGoingToSleepActivities)) {
+ // Still need to tell some activities to sleep; can't sleep yet.
+ if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still need to sleep "
+ + mStackSupervisor.mGoingToSleepActivities.size() + " activities");
+ shouldSleep = false;
+ }
+ }
+
+ if (shouldSleep) {
+ goToSleep();
+ }
+
+ return !shouldSleep;
}
- void goToSleep() {
+ private void goToSleep() {
ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
// Make sure any paused or stopped but visible activities are now sleeping.
@@ -1219,6 +1255,15 @@
}
}
+ private boolean containsActivityFromStack(List<ActivityRecord> rs) {
+ for (ActivityRecord r : rs) {
+ if (r.getStack() == this) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Schedule a pause timeout in case the app doesn't respond. We don't give it much time because
* this directly impacts the responsiveness seen by the user.
@@ -1251,7 +1296,7 @@
if (mPausingActivity != null) {
Slog.wtf(TAG, "Going to pause when pause is already pending for " + mPausingActivity
+ " state=" + mPausingActivity.state);
- if (!mService.isSleepingLocked()) {
+ if (!shouldSleepActivities()) {
// Avoid recursion among check for sleep and complete pause during sleeping.
// Because activity will be paused immediately after resume, just let pause
// be completed by the order of activity paused from clients.
@@ -1411,7 +1456,7 @@
// We can't clobber it, because the stop confirmation will not be handled.
// We don't need to schedule another stop, we only need to let it happen.
prev.state = STOPPING;
- } else if (!prev.visible || mService.isSleepingOrShuttingDownLocked()) {
+ } else if (!prev.visible || shouldSleepOrShutDownActivities()) {
// Clear out any deferred client hide we might currently have.
prev.setDeferHidingClient(false);
// If we were visible then resumeTopActivities will release resources before
@@ -1433,10 +1478,10 @@
if (resumeNext) {
final ActivityStack topStack = mStackSupervisor.getFocusedStack();
- if (!mService.isSleepingOrShuttingDownLocked()) {
+ if (!topStack.shouldSleepOrShutDownActivities()) {
mStackSupervisor.resumeFocusedStackTopActivityLocked(topStack, prev, null);
} else {
- mStackSupervisor.checkReadyForSleepLocked();
+ checkReadyForSleep();
ActivityRecord top = topStack.topRunningActivityLocked();
if (top == null || (prev != null && top != prev)) {
// If there are no more activities available to run, do resume anyway to start
@@ -1502,7 +1547,7 @@
mStackSupervisor.scheduleIdleTimeoutLocked(r);
}
} else {
- mStackSupervisor.checkReadyForSleepLocked();
+ checkReadyForSleep();
}
}
@@ -2211,7 +2256,7 @@
// is skipped.
final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
if (next == null || !next.canTurnScreenOn()) {
- mStackSupervisor.checkReadyForSleepLocked();
+ checkReadyForSleep();
}
return result;
@@ -2296,7 +2341,7 @@
// If we are sleeping, and there is no resumed activity, and the top
// activity is paused, well that is the state we want.
- if (mService.isSleepingOrShuttingDownLocked()
+ if (shouldSleepOrShutDownActivities()
&& mLastPausedActivity == next
&& mStackSupervisor.allPausedActivitiesComplete()) {
// Make sure we have executed any pending transitions, since there
@@ -2388,7 +2433,7 @@
// If the most recent activity was noHistory but was only stopped rather
// than stopped+finished because the device went to sleep, we need to make
// sure to finish it as we're making a new activity topmost.
- if (mService.isSleepingLocked() && mLastNoHistoryActivity != null &&
+ if (shouldSleepActivities() && mLastNoHistoryActivity != null &&
!mLastNoHistoryActivity.finishing) {
if (DEBUG_STATES) Slog.d(TAG_STATES,
"no-history finish of " + mLastNoHistoryActivity + " on new resume");
@@ -3400,7 +3445,7 @@
if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
|| (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
if (!r.finishing) {
- if (!mService.isSleepingLocked()) {
+ if (!shouldSleepActivities()) {
if (DEBUG_STATES) Slog.d(TAG_STATES, "no-history finish of " + r);
if (requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
"stop-no-history", false)) {
@@ -3432,7 +3477,7 @@
EventLogTags.writeAmStopActivity(
r.userId, System.identityHashCode(r), r.shortComponentName);
r.app.thread.scheduleStopActivity(r.appToken, r.visible, r.configChangeFlags);
- if (mService.isSleepingOrShuttingDownLocked()) {
+ if (shouldSleepOrShutDownActivities()) {
r.setSleeping(true);
}
Message msg = mHandler.obtainMessage(STOP_TIMEOUT_MSG, r);
@@ -5278,4 +5323,13 @@
mNoAnimActivities.clear();
ActivityOptions.abort(options);
}
+
+ boolean shouldSleepActivities() {
+ final ActivityStackSupervisor.ActivityDisplay display = getDisplay();
+ return display != null ? display.isSleeping() : mService.isSleepingLocked();
+ }
+
+ boolean shouldSleepOrShutDownActivities() {
+ return shouldSleepActivities() || mService.isShuttingDownLocked();
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index e8bc68f..1c18954 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -105,6 +105,7 @@
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.StackId;
import android.app.ActivityManager.StackInfo;
+import android.app.ActivityManagerInternal.SleepToken;
import android.app.ActivityOptions;
import android.app.AppOpsManager;
import android.app.ProfilerInfo;
@@ -156,6 +157,7 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
+import android.util.TimeUtils;
import android.view.Display;
import com.android.internal.annotations.VisibleForTesting;
@@ -177,6 +179,7 @@
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Iterator;
import java.util.List;
import java.util.Set;
@@ -375,9 +378,6 @@
* is being brought in front of us. */
boolean mUserLeaving = false;
- /** Set when we have taken too long waiting to go to sleep. */
- boolean mSleepTimeout = false;
-
/**
* We don't want to allow the device to go to sleep while in the process
* of launching an activity. This is primarily to allow alarm intent
@@ -393,6 +393,13 @@
*/
PowerManager.WakeLock mGoingToSleep;
+ /**
+ * A list of tokens that cause the top activity to be put to sleep.
+ * They are used by components that may hide and block interaction with underlying
+ * activities.
+ */
+ final ArrayList<SleepToken> mSleepTokens = new ArrayList<SleepToken>();
+
/** Stack id of the front stack when user switched, indexed by userId. */
SparseIntArray mUserStackInFront = new SparseIntArray(2);
@@ -3126,6 +3133,16 @@
return null;
}
+ boolean hasAwakeDisplay() {
+ for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+ final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+ if (!display.shouldSleep()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
void goingToSleepLocked() {
scheduleSleepTimeout();
if (!mGoingToSleep.isHeld()) {
@@ -3138,7 +3155,16 @@
mService.mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
}
}
- checkReadyForSleepLocked();
+
+ applySleepTokensLocked(false /* applyToStacks */);
+
+ checkReadyForSleepLocked(true /* allowDelay */);
+ }
+
+ void prepareForShutdownLocked() {
+ for (int i = 0; i < mActivityDisplays.size(); i++) {
+ createSleepTokenLocked("shutdown", mActivityDisplays.keyAt(i));
+ }
}
boolean shutdownLocked(int timeout) {
@@ -3151,7 +3177,8 @@
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
- cantShutdown |= stacks.get(stackNdx).checkReadyForSleepLocked();
+ cantShutdown |=
+ stacks.get(stackNdx).goToSleepIfPossible(true /* shuttingDown */);
}
}
if (cantShutdown) {
@@ -3172,8 +3199,7 @@
}
// Force checkReadyForSleep to complete.
- mSleepTimeout = true;
- checkReadyForSleepLocked();
+ checkReadyForSleepLocked(false /* allowDelay */);
return timedout;
}
@@ -3183,54 +3209,75 @@
if (mGoingToSleep.isHeld()) {
mGoingToSleep.release();
}
+ }
+
+ void applySleepTokensLocked(boolean applyToStacks) {
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+ // Set the sleeping state of the display.
+ final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+ final boolean displayShouldSleep = display.shouldSleep();
+ if (displayShouldSleep == display.isSleeping()) {
+ continue;
+ }
+ display.setIsSleeping(displayShouldSleep);
+
+ if (!applyToStacks) {
+ continue;
+ }
+
+ // Set the sleeping state of the stacks on the display.
+ final ArrayList<ActivityStack> stacks = display.mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
- stack.awakeFromSleepingLocked();
- if (isFocusedStack(stack)) {
- resumeFocusedStackTopActivityLocked();
+ if (displayShouldSleep) {
+ stack.goToSleepIfPossible(false /* shuttingDown */);
+ } else {
+ stack.awakeFromSleepingLocked();
+ if (isFocusedStack(stack)) {
+ resumeFocusedStackTopActivityLocked();
+ }
+ }
+ }
+
+ if (displayShouldSleep || mGoingToSleepActivities.isEmpty()) {
+ continue;
+ }
+ // The display is awake now, so clean up the going to sleep list.
+ for (Iterator<ActivityRecord> it = mGoingToSleepActivities.iterator(); it.hasNext(); ) {
+ final ActivityRecord r = it.next();
+ if (r.getDisplayId() == display.mDisplayId) {
+ it.remove();
}
}
}
- mGoingToSleepActivities.clear();
}
void activitySleptLocked(ActivityRecord r) {
mGoingToSleepActivities.remove(r);
- checkReadyForSleepLocked();
+ final ActivityStack s = r.getStack();
+ if (s != null) {
+ s.checkReadyForSleep();
+ } else {
+ checkReadyForSleepLocked(true);
+ }
}
- void checkReadyForSleepLocked() {
+ void checkReadyForSleepLocked(boolean allowDelay) {
if (!mService.isSleepingOrShuttingDownLocked()) {
// Do not care.
return;
}
- if (!mSleepTimeout) {
+ if (allowDelay) {
boolean dontSleep = false;
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+ final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+ final ArrayList<ActivityStack> stacks = display.mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
- dontSleep |= stacks.get(stackNdx).checkReadyForSleepLocked();
+ dontSleep |= stacks.get(stackNdx).goToSleepIfPossible(false /* shuttingDown */);
}
}
- if (mStoppingActivities.size() > 0) {
- // Still need to tell some activities to stop; can't sleep yet.
- if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still need to stop "
- + mStoppingActivities.size() + " activities");
- scheduleIdleLocked();
- dontSleep = true;
- }
-
- if (mGoingToSleepActivities.size() > 0) {
- // Still need to tell some activities to sleep; can't sleep yet.
- if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still need to sleep "
- + mGoingToSleepActivities.size() + " activities");
- dontSleep = true;
- }
-
if (dontSleep) {
return;
}
@@ -3239,13 +3286,6 @@
// Send launch end powerhint before going sleep
mService.mActivityStarter.sendPowerHintForLaunchEndIfNeeded();
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
- for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
- stacks.get(stackNdx).goToSleep();
- }
- }
-
removeSleepTimeouts();
if (mGoingToSleep.isHeld()) {
@@ -3516,21 +3556,27 @@
s.setVisibility(false);
}
}
- if ((!waitingVisible || mService.isSleepingOrShuttingDownLocked()) && remove) {
- if (!processPausingActivities && s.state == PAUSING) {
- // Defer processing pausing activities in this iteration and reschedule
- // a delayed idle to reprocess it again
- removeTimeoutsForActivityLocked(idleActivity);
- scheduleIdleTimeoutLocked(idleActivity);
- continue;
- }
+ if (remove) {
+ final ActivityStack stack = s.getStack();
+ final boolean shouldSleepOrShutDown = stack != null
+ ? stack.shouldSleepOrShutDownActivities()
+ : mService.isSleepingOrShuttingDownLocked();
+ if (!waitingVisible || shouldSleepOrShutDown) {
+ if (!processPausingActivities && s.state == PAUSING) {
+ // Defer processing pausing activities in this iteration and reschedule
+ // a delayed idle to reprocess it again
+ removeTimeoutsForActivityLocked(idleActivity);
+ scheduleIdleTimeoutLocked(idleActivity);
+ continue;
+ }
- if (DEBUG_STATES) Slog.v(TAG, "Ready to stop: " + s);
- if (stops == null) {
- stops = new ArrayList<>();
+ if (DEBUG_STATES) Slog.v(TAG, "Ready to stop: " + s);
+ if (stops == null) {
+ stops = new ArrayList<>();
+ }
+ stops.add(s);
+ mStoppingActivities.remove(activityNdx);
}
- stops.add(s);
- mStoppingActivities.remove(activityNdx);
}
}
@@ -3583,7 +3629,6 @@
public void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("mFocusedStack=" + mFocusedStack);
pw.print(" mLastFocusedStack="); pw.println(mLastFocusedStack);
- pw.print(prefix); pw.println("mSleepTimeout=" + mSleepTimeout);
pw.print(prefix);
pw.println("mCurTaskIdForUser=" + mCurTaskIdForUser);
pw.print(prefix); pw.println("mUserStackInFront=" + mUserStackInFront);
@@ -3680,6 +3725,8 @@
stackHeader.append("\n");
stackHeader.append(" mFullscreen=" + stack.mFullscreen);
stackHeader.append("\n");
+ stackHeader.append(" isSleeping=" + stack.shouldSleepActivities());
+ stackHeader.append("\n");
stackHeader.append(" mBounds=" + stack.mBounds);
final boolean printedStackHeader = stack.dumpActivitiesLocked(fd, pw, dumpAll,
@@ -3731,8 +3778,6 @@
" Activities waiting for another to become visible:", null);
printed |= dumpHistoryList(fd, pw, mGoingToSleepActivities, " ", "Sleep", false, !dumpAll,
false, dumpPackage, true, " Activities waiting to sleep:", null);
- printed |= dumpHistoryList(fd, pw, mGoingToSleepActivities, " ", "Sleep", false, !dumpAll,
- false, dumpPackage, true, " Activities waiting to sleep:", null);
return printed;
}
@@ -3843,7 +3888,6 @@
}
void removeSleepTimeouts() {
- mSleepTimeout = false;
mHandler.removeMessages(SLEEP_TIMEOUT_MSG);
}
@@ -3945,6 +3989,9 @@
moveTasksToFullscreenStackLocked(stack.getStackId(), true /* onTop */);
}
}
+
+ releaseSleepTokens(activityDisplay);
+
mActivityDisplays.remove(displayId);
mWindowManager.onDisplayRemoved(displayId);
}
@@ -3955,12 +4002,60 @@
synchronized (mService) {
ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
if (activityDisplay != null) {
+ // The window policy is responsible for stopping activities on the default display
+ if (displayId != Display.DEFAULT_DISPLAY) {
+ int displayState = activityDisplay.mDisplay.getState();
+ if (displayState == Display.STATE_OFF && activityDisplay.mOffToken == null) {
+ activityDisplay.mOffToken =
+ mService.acquireSleepToken("Display-off", displayId);
+ } else if (displayState == Display.STATE_ON
+ && activityDisplay.mOffToken != null) {
+ activityDisplay.mOffToken.release();
+ activityDisplay.mOffToken = null;
+ }
+ }
// TODO: Update the bounds.
}
mWindowManager.onDisplayChanged(displayId);
}
}
+ SleepToken createSleepTokenLocked(String tag, int displayId) {
+ ActivityDisplay display = mActivityDisplays.get(displayId);
+ if (display == null) {
+ throw new IllegalArgumentException("Invalid display: " + displayId);
+ }
+
+ final SleepTokenImpl token = new SleepTokenImpl(tag, displayId);
+ mSleepTokens.add(token);
+ display.mAllSleepTokens.add(token);
+ return token;
+ }
+
+ private void removeSleepTokenLocked(SleepTokenImpl token) {
+ mSleepTokens.remove(token);
+
+ ActivityDisplay display = mActivityDisplays.get(token.mDisplayId);
+ if (display != null) {
+ display.mAllSleepTokens.remove(token);
+ if (display.mAllSleepTokens.isEmpty()) {
+ mService.updateSleepIfNeededLocked();
+ }
+ }
+ }
+
+ private void releaseSleepTokens(ActivityDisplay display) {
+ if (display.mAllSleepTokens.isEmpty()) {
+ return;
+ }
+ for (SleepTokenImpl token : display.mAllSleepTokens) {
+ mSleepTokens.remove(token);
+ }
+ display.mAllSleepTokens.clear();
+
+ mService.updateSleepIfNeededLocked();
+ }
+
private StackInfo getStackInfoLocked(ActivityStack stack) {
final int displayId = stack.mDisplayId;
final ActivityDisplay display = mActivityDisplays.get(displayId);
@@ -4266,9 +4361,9 @@
void activityRelaunchedLocked(IBinder token) {
mWindowManager.notifyAppRelaunchingFinished(token);
- if (mService.isSleepingOrShuttingDownLocked()) {
- final ActivityRecord r = ActivityRecord.isInStackLocked(token);
- if (r != null) {
+ final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+ if (r != null) {
+ if (r.getStack().shouldSleepOrShutDownActivities()) {
r.setSleeping(true, true);
}
}
@@ -4420,8 +4515,7 @@
synchronized (mService) {
if (mService.isSleepingOrShuttingDownLocked()) {
Slog.w(TAG, "Sleep timeout! Sleeping now.");
- mSleepTimeout = true;
- checkReadyForSleepLocked();
+ checkReadyForSleepLocked(false /* allowDelay */);
}
}
} break;
@@ -4546,6 +4640,13 @@
/** Array of all UIDs that are present on the display. */
private IntArray mDisplayAccessUIDs = new IntArray();
+ /** All tokens used to put activities on this stack to sleep (including mOffToken) */
+ final ArrayList<SleepTokenImpl> mAllSleepTokens = new ArrayList<>();
+ /** The token acquired by ActivityStackSupervisor to put stacks on the display to sleep */
+ SleepToken mOffToken;
+
+ private boolean mSleeping;
+
@VisibleForTesting
ActivityDisplay() {
mActivityDisplays.put(mDisplayId, this);
@@ -4570,12 +4671,14 @@
if (DEBUG_STACK) Slog.v(TAG_STACK, "attachStack: attaching " + stack
+ " to displayId=" + mDisplayId + " position=" + position);
mStacks.add(position, stack);
+ mService.updateSleepIfNeededLocked();
}
void detachStack(ActivityStack stack) {
if (DEBUG_STACK) Slog.v(TAG_STACK, "detachStack: detaching " + stack
+ " from displayId=" + mDisplayId);
mStacks.remove(stack);
+ mService.updateSleepIfNeededLocked();
}
@Override
@@ -4623,6 +4726,19 @@
boolean shouldDestroyContentOnRemove() {
return mDisplay.getRemoveMode() == REMOVE_MODE_DESTROY_CONTENT;
}
+
+ boolean shouldSleep() {
+ return (mStacks.isEmpty() || !mAllSleepTokens.isEmpty())
+ && (mService.mRunningVoice == null);
+ }
+
+ boolean isSleeping() {
+ return mSleeping;
+ }
+
+ void setIsSleeping(boolean asleep) {
+ mSleeping = asleep;
+ }
}
ActivityStack findStackBehind(ActivityStack stack) {
@@ -4804,4 +4920,30 @@
mResult.dump(pw, prefix);
}
}
+
+ private final class SleepTokenImpl extends SleepToken {
+ private final String mTag;
+ private final long mAcquireTime;
+ private final int mDisplayId;
+
+ public SleepTokenImpl(String tag, int displayId) {
+ mTag = tag;
+ mDisplayId = displayId;
+ mAcquireTime = SystemClock.uptimeMillis();
+ }
+
+ @Override
+ public void release() {
+ synchronized (mService) {
+ removeSleepTokenLocked(this);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "{\"" + mTag + "\", display " + mDisplayId
+ + ", acquire at " + TimeUtils.formatUptime(mAcquireTime) + "}";
+ }
+ }
+
}
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index 58e71df..cea80c8 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -18,6 +18,7 @@
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
@@ -32,6 +33,7 @@
import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_UNOCCLUDE;
import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
+import android.app.ActivityManagerInternal.SleepToken;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.Trace;
@@ -63,6 +65,7 @@
private ActivityRecord mDismissingKeyguardActivity;
private int mBeforeUnoccludeTransit;
private int mVisibilityTransactionDepth;
+ private SleepToken mSleepToken;
KeyguardController(ActivityManagerService service,
ActivityStackSupervisor stackSupervisor) {
@@ -102,7 +105,7 @@
mDismissalRequested = false;
}
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
- mService.updateSleepIfNeededLocked();
+ updateKeyguardSleepToken();
}
/**
@@ -122,7 +125,7 @@
mWindowManager.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
false /* alwaysKeepCurrent */, convertTransitFlags(flags),
false /* forceOverride */);
- mService.updateSleepIfNeededLocked();
+ updateKeyguardSleepToken();
// Some stack visibility might change (e.g. docked stack)
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
@@ -263,7 +266,7 @@
try {
mWindowManager.prepareAppTransition(resolveOccludeTransit(),
false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
- mService.updateSleepIfNeededLocked();
+ updateKeyguardSleepToken();
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
mWindowManager.executeAppTransition();
} finally {
@@ -333,6 +336,15 @@
}
}
+ private void updateKeyguardSleepToken() {
+ if (mSleepToken == null && isKeyguardShowing()) {
+ mSleepToken = mService.acquireSleepToken("Keyguard", DEFAULT_DISPLAY);
+ } else if (mSleepToken != null && !isKeyguardShowing()) {
+ mSleepToken.release();
+ mSleepToken = null;
+ }
+ }
+
void dump(PrintWriter pw, String prefix) {
pw.println(prefix + "KeyguardController:");
pw.println(prefix + " mKeyguardShowing=" + mKeyguardShowing);
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 88d8944..617ba96 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -96,6 +96,7 @@
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -1580,8 +1581,9 @@
// A task can not be docked even if it is considered resizeable because it only supports
// picture-in-picture mode but has a non-resizeable resizeMode
return mService.mSupportsSplitScreenMultiWindow
- && isResizeable(false /* checkSupportsPip */)
- && !ActivityInfo.isPreserveOrientationMode(mResizeMode);
+ && (mService.mForceResizableActivities
+ || (isResizeable(false /* checkSupportsPip */)
+ && !ActivityInfo.isPreserveOrientationMode(mResizeMode)));
}
/**
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index e82eabf..56cff7c 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -305,8 +305,8 @@
* In order to support the always-on feature, an app has to
* <ul>
* <li>target {@link VERSION_CODES#N API 24} or above, and
- * <li>not opt out through the {@link VpnService#METADATA_SUPPORTS_ALWAYS_ON} meta-data
- * field.
+ * <li>not opt out through the {@link VpnService#SERVICE_META_DATA_SUPPORTS_ALWAYS_ON}
+ * meta-data field.
* </ul>
*
* @param packageName the canonical package name of the VPN app
@@ -340,8 +340,8 @@
for (ResolveInfo rInfo : services) {
final Bundle metaData = rInfo.serviceInfo.metaData;
- if (metaData != null
- && !metaData.getBoolean(VpnService.METADATA_SUPPORTS_ALWAYS_ON, true)) {
+ if (metaData != null &&
+ !metaData.getBoolean(VpnService.SERVICE_META_DATA_SUPPORTS_ALWAYS_ON, true)) {
return false;
}
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
index 55e290a..ad661d7 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
@@ -60,6 +60,8 @@
private final Handler mHandler;
private final OffloadHardwareInterface mHwInterface;
private final ContentResolver mContentResolver;
+ private final INetworkManagementService mNms;
+ private final ITetheringStatsProvider mStatsProvider;
private final SharedLog mLog;
private boolean mConfigInitialized;
private boolean mControlInitialized;
@@ -89,13 +91,14 @@
mHandler = h;
mHwInterface = hwi;
mContentResolver = contentResolver;
+ mNms = nms;
+ mStatsProvider = new OffloadTetheringStatsProvider();
mLog = log.forSubComponent(TAG);
mExemptPrefixes = new HashSet<>();
mLastLocalPrefixStrs = new HashSet<>();
try {
- nms.registerTetheringStatsProvider(
- new OffloadTetheringStatsProvider(), getClass().getSimpleName());
+ mNms.registerTetheringStatsProvider(mStatsProvider, getClass().getSimpleName());
} catch (RemoteException e) {
mLog.e("Cannot register offload stats provider: " + e);
}
@@ -150,7 +153,26 @@
@Override
public void onStoppedLimitReached() {
mLog.log("onStoppedLimitReached");
- // Poll for statistics and notify NetworkStats
+
+ // We cannot reliably determine on which interface the limit was reached,
+ // because the HAL interface does not specify it. We cannot just use the
+ // current upstream, because that might have changed since the time that
+ // the HAL queued the callback.
+ // TODO: rev the HAL so that it provides an interface name.
+
+ // Fetch current stats, so that when our notification reaches
+ // NetworkStatsService and triggers a poll, we will respond with
+ // current data (which will be above the limit that was reached).
+ // Note that if we just changed upstream, this is unnecessary but harmless.
+ // The stats for the previous upstream were already updated on this thread
+ // just after the upstream was changed, so they are also up-to-date.
+ updateStatsForCurrentUpstream();
+
+ try {
+ mNms.tetherLimitReached(mStatsProvider);
+ } catch (RemoteException e) {
+ mLog.e("Cannot report data limit reached: " + e);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index f41aa5f..a9c0cb0 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -3354,12 +3354,6 @@
int downstreamActivity;
int upstreamActivity;
- if (!syncOperation.isPeriodic) {
- // mSyncJobService.jobFinidhed is async, we need to ensure that this job is
- // removed from JobScheduler's pending jobs list before moving forward and
- // potentially rescheduling all pending jobs to respect new backoff values.
- getJobScheduler().cancel(syncOperation.jobId);
- }
mLogger.log("runSyncFinishedOrCanceledH() op=", syncOperation, " result=", syncResult);
if (syncResult != null) {
@@ -3368,6 +3362,16 @@
+ syncOperation + ", result " + syncResult);
}
+ // In the non-canceled case, close the active sync context before doing the rest
+ // of the stuff.
+ closeActiveSyncContext(activeSyncContext);
+
+ // Note this part is probably okay to do before closeActiveSyncContext()...
+ // But moved here to restore OC-dev's behavior. See b/64597061.
+ if (!syncOperation.isPeriodic) {
+ getJobScheduler().cancel(syncOperation.jobId);
+ }
+
if (!syncResult.hasError()) {
historyMessage = SyncStorageEngine.MESG_SUCCESS;
// TODO: set these correctly when the SyncResult is extended to include it
@@ -3404,6 +3408,11 @@
if (isLoggable) {
Slog.v(TAG, "runSyncFinishedOrCanceled [canceled]: " + syncOperation);
}
+
+ if (!syncOperation.isPeriodic) {
+ getJobScheduler().cancel(syncOperation.jobId);
+ }
+
if (activeSyncContext.mSyncAdapter != null) {
try {
mLogger.log("Calling cancelSync for runSyncFinishedOrCanceled ",
@@ -3418,10 +3427,10 @@
historyMessage = SyncStorageEngine.MESG_CANCELED;
downstreamActivity = 0;
upstreamActivity = 0;
- }
- // Close and unbind the service. Don't use activeSyncContext.mSyncAdapter after this.
- closeActiveSyncContext(activeSyncContext);
+ // In the cancel sync case, close it after calling cancelSync().
+ closeActiveSyncContext(activeSyncContext);
+ }
stopSyncEvent(activeSyncContext.mHistoryRowId, syncOperation, historyMessage,
upstreamActivity, downstreamActivity, elapsedTime);
@@ -3457,6 +3466,8 @@
+ activeSyncContext.toString());
}
mSyncHandler.removeMessages(SyncHandler.MESSAGE_MONITOR_SYNC, activeSyncContext);
+
+ mLogger.log("closeActiveSyncContext: ", activeSyncContext);
}
/**
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 3d24fed..9aabdab 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -59,6 +59,13 @@
private static final int MSG_UPDATE_AMBIENT_LUX = 1;
private static final int MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE = 2;
+ // Length of the ambient light horizon used to calculate the long term estimate of ambient
+ // light.
+ private static final int AMBIENT_LIGHT_LONG_HORIZON_MILLIS = 10000;
+
+ // Length of the ambient light horizon used to calculate short-term estimate of ambient light.
+ private static final int AMBIENT_LIGHT_SHORT_HORIZON_MILLIS = 2000;
+
// Callbacks for requesting updates to the display's power state
private final Callbacks mCallbacks;
@@ -345,22 +352,51 @@
}
private void setAmbientLux(float lux) {
+ if (DEBUG) {
+ Slog.d(TAG, "setAmbientLux(" + lux + ")");
+ }
mAmbientLux = lux;
mBrighteningLuxThreshold = mDynamicHysteresis.getBrighteningThreshold(lux);
mDarkeningLuxThreshold = mDynamicHysteresis.getDarkeningThreshold(lux);
}
- private float calculateAmbientLux(long now) {
+ private float calculateAmbientLux(long now, long horizon) {
+ if (DEBUG) {
+ Slog.d(TAG, "calculateAmbientLux(" + now + ", " + horizon + ")");
+ }
final int N = mAmbientLightRingBuffer.size();
if (N == 0) {
Slog.e(TAG, "calculateAmbientLux: No ambient light readings available");
return -1;
}
+
+ // Find the first measurement that is just outside of the horizon.
+ int endIndex = 0;
+ final long horizonStartTime = now - horizon;
+ for (int i = 0; i < N-1; i++) {
+ if (mAmbientLightRingBuffer.getTime(i + 1) <= horizonStartTime) {
+ endIndex++;
+ } else {
+ break;
+ }
+ }
+ if (DEBUG) {
+ Slog.d(TAG, "calculateAmbientLux: selected endIndex=" + endIndex + ", point=("
+ + mAmbientLightRingBuffer.getTime(endIndex) + ", "
+ + mAmbientLightRingBuffer.getLux(endIndex)
+ + ")");
+ }
float sum = 0;
float totalWeight = 0;
long endTime = AMBIENT_LIGHT_PREDICTION_TIME_MILLIS;
- for (int i = N - 1; i >= 0; i--) {
- long startTime = (mAmbientLightRingBuffer.getTime(i) - now);
+ for (int i = N - 1; i >= endIndex; i--) {
+ long eventTime = mAmbientLightRingBuffer.getTime(i);
+ if (i == endIndex && eventTime < horizonStartTime) {
+ // If we're at the final value, make sure we only consider the part of the sample
+ // within our desired horizon.
+ eventTime = horizonStartTime;
+ }
+ final long startTime = eventTime - now;
float weight = calculateWeight(startTime, endTime);
float lux = mAmbientLightRingBuffer.getLux(i);
if (DEBUG) {
@@ -435,7 +471,7 @@
timeWhenSensorWarmedUp);
return;
}
- setAmbientLux(calculateAmbientLux(time));
+ setAmbientLux(calculateAmbientLux(time, AMBIENT_LIGHT_SHORT_HORIZON_MILLIS));
mAmbientLuxValid = true;
if (DEBUG) {
Slog.d(TAG, "updateAmbientLux: Initializing: "
@@ -447,14 +483,25 @@
long nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
long nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
- float ambientLux = calculateAmbientLux(time);
+ // Essentially, we calculate both a slow ambient lux, to ensure there's a true long-term
+ // change in lighting conditions, and a fast ambient lux to determine what the new
+ // brightness situation is since the slow lux can be quite slow to converge.
+ //
+ // Note that both values need to be checked for sufficient change before updating the
+ // proposed ambient light value since the slow value might be sufficiently far enough away
+ // from the fast value to cause a recalculation while its actually just converging on
+ // the fast value still.
+ float slowAmbientLux = calculateAmbientLux(time, AMBIENT_LIGHT_LONG_HORIZON_MILLIS);
+ float fastAmbientLux = calculateAmbientLux(time, AMBIENT_LIGHT_SHORT_HORIZON_MILLIS);
- if (ambientLux >= mBrighteningLuxThreshold && nextBrightenTransition <= time
- || ambientLux <= mDarkeningLuxThreshold && nextDarkenTransition <= time) {
- setAmbientLux(ambientLux);
+ if (slowAmbientLux >= mBrighteningLuxThreshold &&
+ fastAmbientLux >= mBrighteningLuxThreshold && nextBrightenTransition <= time
+ || slowAmbientLux <= mDarkeningLuxThreshold
+ && fastAmbientLux <= mDarkeningLuxThreshold && nextDarkenTransition <= time) {
+ setAmbientLux(fastAmbientLux);
if (DEBUG) {
Slog.d(TAG, "updateAmbientLux: "
- + ((ambientLux > mAmbientLux) ? "Brightened" : "Darkened") + ": "
+ + ((fastAmbientLux > mAmbientLux) ? "Brightened" : "Darkened") + ": "
+ "mBrighteningLuxThreshold=" + mBrighteningLuxThreshold
+ ", mAmbientLightRingBuffer=" + mAmbientLightRingBuffer
+ ", mAmbientLux=" + mAmbientLux);
@@ -616,6 +663,12 @@
void updateBrightness();
}
+ /**
+ * A ring buffer of ambient light measurements sorted by time.
+ *
+ * Each entry consists of a timestamp and a lux measurement, and the overall buffer is sorted
+ * from oldest to newest.
+ */
private static final class AmbientLightRingBuffer {
// Proportional extra capacity of the buffer beyond the expected number of light samples
// in the horizon
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index fb8ae12..e316fff 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -1010,7 +1010,9 @@
// contents of the screen.
mPowerState.prepareColorFade(mContext,
mColorFadeFadesConfig ? ColorFade.MODE_FADE : ColorFade.MODE_WARM_UP);
- mColorFadeOffAnimator.end();
+ if (mColorFadeOffAnimator != null) {
+ mColorFadeOffAnimator.end();
+ }
// Some display hardware will blank itself on the transition between doze and non-doze
// but still on display states. In this case we want to report to policy that the
// display has turned off so it can prepare the appropriate power on animation, but we
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 0072ba4..f88a074 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -3046,9 +3046,7 @@
updateRestrictBackgroundRulesOnUidStatusChangedUL(uid, oldUidState, uidState);
if (isProcStateAllowedWhileIdleOrPowerSaveMode(oldUidState)
!= isProcStateAllowedWhileIdleOrPowerSaveMode(uidState) ) {
- if (isUidIdle(uid)) {
- updateRuleForAppIdleUL(uid);
- }
+ updateRuleForAppIdleUL(uid);
if (mDeviceIdleMode) {
updateRuleForDeviceIdleUL(uid);
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 28acd9a..845efa6 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -804,6 +804,7 @@
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
mZenModeHelper.updateDefaultZenRules();
+ mRankingHelper.onLocaleChanged(context, ActivityManager.getCurrentUser());
}
}
};
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 9622a24..3386fe83 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -1073,6 +1073,22 @@
}
}
+ protected void onLocaleChanged(Context context, int userId) {
+ synchronized (mRecords) {
+ int N = mRecords.size();
+ for (int i = 0; i < N; i++) {
+ Record record = mRecords.valueAt(i);
+ if (UserHandle.getUserId(record.uid) == userId) {
+ if (record.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
+ record.channels.get(NotificationChannel.DEFAULT_CHANNEL_ID).setName(
+ context.getResources().getString(
+ R.string.default_notification_channel_label));
+ }
+ }
+ }
+ }
+ }
+
public void onPackagesChanged(boolean removingPackage, int changeUserId, String[] pkgList,
int[] uidList) {
if (pkgList == null || pkgList.length == 0) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index d99408f..56835f6 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -4867,7 +4867,7 @@
pw.print(" enabled=");
pw.print(ps.getEnabled(user.id));
pw.print(" instant=");
- pw.println(ps.getInstantApp(user.id));
+ pw.print(ps.getInstantApp(user.id));
pw.print(" virtual=");
pw.println(ps.getVirtulalPreload(user.id));
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index ae78d7c..3c11a53 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -7466,10 +7466,12 @@
}
}
+ // TODO (multidisplay): Support multiple displays in WindowManagerPolicy.
private void updateDreamingSleepToken(boolean acquire) {
if (acquire) {
if (mDreamingSleepToken == null) {
- mDreamingSleepToken = mActivityManagerInternal.acquireSleepToken("Dream");
+ mDreamingSleepToken = mActivityManagerInternal.acquireSleepToken(
+ "Dream", Display.DEFAULT_DISPLAY);
}
} else {
if (mDreamingSleepToken != null) {
@@ -7479,10 +7481,12 @@
}
}
+ // TODO (multidisplay): Support multiple displays in WindowManagerPolicy.
private void updateScreenOffSleepToken(boolean acquire) {
if (acquire) {
if (mScreenOffSleepToken == null) {
- mScreenOffSleepToken = mActivityManagerInternal.acquireSleepToken("ScreenOff");
+ mScreenOffSleepToken = mActivityManagerInternal.acquireSleepToken(
+ "ScreenOff", Display.DEFAULT_DISPLAY);
}
} else {
if (mScreenOffSleepToken != null) {
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index d1a5953..63900e0 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -715,6 +715,7 @@
* @param reason reason for reboot/shutdown
*/
public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
+ SHUTDOWN_TIMINGS_LOG.traceEnd(); // SystemServerShutdown
if (reboot) {
Log.i(TAG, "Rebooting, reason: " + reason);
PowerManagerService.lowLevelReboot(reason);
@@ -736,7 +737,6 @@
} catch (InterruptedException unused) {
}
}
- SHUTDOWN_TIMINGS_LOG.traceEnd(); // SystemServerShutdown
// Shutdown power
Log.i(TAG, "Performing low-level shutdown...");
PowerManagerService.lowLevelShutdown(reason);
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index 2b3901b..c2edc04 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -16,8 +16,8 @@
package com.android.server.wm;
+import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
-
import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
@@ -358,7 +358,7 @@
// This must be called while inside a transaction.
boolean stepAnimationLocked(long currentTime) {
- if (mService.okToAnimate()) {
+ if (mAppToken.okToAnimate()) {
// We will run animations as long as the display isn't frozen.
if (animation == sDummyAnimation) {
@@ -423,8 +423,8 @@
if (DEBUG_ANIM) Slog.v(TAG, "Animation done in " + mAppToken
+ ": reportedVisible=" + mAppToken.reportedVisible
- + " okToDisplay=" + mService.okToDisplay()
- + " okToAnimate=" + mService.okToAnimate()
+ + " okToDisplay=" + mAppToken.okToDisplay()
+ + " okToAnimate=" + mAppToken.okToAnimate()
+ " startingDisplayed=" + mAppToken.startingDisplayed);
transformation.clear();
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
index dce06f4..f142ff6 100644
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static com.android.server.wm.AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS;
@@ -401,7 +402,7 @@
// If we are preparing an app transition, then delay changing
// the visibility of this token until we execute that transition.
- if (mService.okToAnimate() && mService.mAppTransition.isTransitionSet()) {
+ if (wtoken.okToAnimate() && mService.mAppTransition.isTransitionSet()) {
// A dummy animation is a placeholder animation which informs others that an
// animation is going on (in this case an application transition). If the animation
// was transferred from another application/animator, no dummy animator should be
@@ -478,7 +479,7 @@
// If the display is frozen, we won't do anything until the actual window is
// displayed so there is no reason to put in the starting window.
- if (!mService.okToDisplay()) {
+ if (!mContainer.okToDisplay()) {
return false;
}
@@ -702,16 +703,17 @@
public void startFreezingScreen(int configChanges) {
synchronized(mWindowMap) {
- if (configChanges == 0 && mService.okToDisplay()) {
- if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + mToken);
- return;
- }
-
if (mContainer == null) {
Slog.w(TAG_WM,
"Attempted to freeze screen with non-existing app token: " + mContainer);
return;
}
+
+ if (configChanges == 0 && mContainer.okToDisplay()) {
+ if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + mToken);
+ return;
+ }
+
mContainer.startFreezingScreen();
}
}
diff --git a/services/core/java/com/android/server/wm/DimLayerController.java b/services/core/java/com/android/server/wm/DimLayerController.java
index 7414928..6f9e45a 100644
--- a/services/core/java/com/android/server/wm/DimLayerController.java
+++ b/services/core/java/com/android/server/wm/DimLayerController.java
@@ -290,7 +290,7 @@
state.dimLayer.setLayer(dimLayer);
}
if (state.dimLayer.isAnimating()) {
- if (!mDisplayContent.mService.okToAnimate()) {
+ if (!mDisplayContent.okToAnimate()) {
// Jump to the end of the animation.
state.dimLayer.show();
} else {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 5bc4a6b..f0a375b 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -3204,6 +3204,19 @@
mService.requestTraversal();
}
+ boolean okToDisplay() {
+ if (mDisplayId == DEFAULT_DISPLAY) {
+ return !mService.mDisplayFrozen
+ && mService.mDisplayEnabled && mService.mPolicy.isScreenOn();
+ }
+ return mDisplayInfo.state == Display.STATE_ON;
+ }
+
+ boolean okToAnimate() {
+ return okToDisplay() &&
+ (mDisplayId != DEFAULT_DISPLAY || mService.mPolicy.okToAnimate());
+ }
+
static final class TaskForResizePointSearchResult {
boolean searchDone;
Task taskForResize;
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 940ad33..4e4d42d 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -102,6 +102,11 @@
*/
private final boolean mIsRunningOnIoT;
+ /**
+ * Flag indicating whether we are running on an Android Wear device.
+ */
+ private final boolean mIsRunningOnWear;
+
TaskSnapshotController(WindowManagerService service) {
mService = service;
mCache = new TaskSnapshotCache(mService, mLoader);
@@ -109,6 +114,8 @@
PackageManager.FEATURE_LEANBACK);
mIsRunningOnIoT = mService.mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_EMBEDDED);
+ mIsRunningOnWear = mService.mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_WATCH);
}
void systemReady() {
@@ -213,8 +220,7 @@
}
private boolean shouldDisableSnapshots() {
- return !ENABLE_TASK_SNAPSHOTS || ActivityManager.isLowRamDeviceStatic()
- || mIsRunningOnTv || mIsRunningOnIoT;
+ return !ENABLE_TASK_SNAPSHOTS || mIsRunningOnWear || mIsRunningOnTv || mIsRunningOnIoT;
}
private Rect minRect(Rect rect1, Rect rect2) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 5c664c2..e7f3de0b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2347,7 +2347,7 @@
// artifacts when we unfreeze the display if some different animation
// is running.
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "WM#applyAnimationLocked");
- if (okToAnimate()) {
+ if (atoken.okToAnimate()) {
final DisplayContent displayContent = atoken.getTask().getDisplayContent();
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
final int width = displayInfo.appWidth;
@@ -2425,14 +2425,6 @@
return false;
}
- boolean okToDisplay() {
- return !mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOn();
- }
-
- boolean okToAnimate() {
- return okToDisplay() && mPolicy.okToAnimate();
- }
-
@Override
public void addWindowToken(IBinder binder, int type, int displayId) {
if (!checkCallingPermission(MANAGE_APP_TOKENS, "addWindowToken()")) {
@@ -2699,7 +2691,9 @@
synchronized(mWindowMap) {
boolean prepared = mAppTransition.prepareAppTransitionLocked(transit, alwaysKeepCurrent,
flags, forceOverride);
- if (prepared && okToAnimate()) {
+ // TODO (multidisplay): associate app transitions with displays
+ final DisplayContent dc = mRoot.getDisplayContent(DEFAULT_DISPLAY);
+ if (prepared && dc != null && dc.okToAnimate()) {
mSkipAppTransitionAnimation = false;
}
}
@@ -5817,7 +5811,10 @@
// If the screen is currently frozen or off, then keep
// it frozen/off until this window draws at its new
// orientation.
- if (!okToDisplay() && mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
+ // TODO (multidisplay): Support screen freezing on secondary displays.
+ final DisplayContent dc = mRoot.getDisplayContent(DEFAULT_DISPLAY);
+ if ((dc == null || !dc.okToDisplay())
+ && mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Changing surface while display frozen: " + w);
w.setOrientationChanging(true);
w.mLastFreezeDuration = 0;
@@ -6033,7 +6030,7 @@
return;
}
- if (!displayContent.isReady() || !mPolicy.isScreenOn() || !okToAnimate()) {
+ if (!displayContent.isReady() || !mPolicy.isScreenOn() || !displayContent.okToAnimate()) {
// No need to freeze the screen before the display is ready, if the screen is off,
// or we can't currently animate.
return;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 2b258c9..da739ac 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1711,7 +1711,7 @@
final boolean adjustedForMinimizedDockOrIme = task != null
&& (task.mStack.isAdjustedForMinimizedDockedStack()
|| task.mStack.isAdjustedForIme());
- if (mService.okToAnimate()
+ if (mToken.okToAnimate()
&& (mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
&& !isDragResizing() && !adjustedForMinimizedDockOrIme
&& (task == null || getTask().mStack.hasMovementAnimations())
@@ -1880,7 +1880,7 @@
// First, see if we need to run an animation. If we do, we have to hold off on removing the
// window until the animation is done. If the display is frozen, just remove immediately,
// since the animation wouldn't be seen.
- if (mHasSurface && mService.okToAnimate()) {
+ if (mHasSurface && mToken.okToAnimate()) {
if (mWillReplaceWindow) {
// This window is going to be replaced. We need to keep it around until the new one
// gets added, then we will get rid of this one.
@@ -2315,7 +2315,7 @@
mLayoutNeeded = true;
}
- if (isDrawnLw() && mService.okToAnimate()) {
+ if (isDrawnLw() && mToken.okToAnimate()) {
mWinAnimator.applyEnterAnimationLocked();
}
}
@@ -2471,7 +2471,7 @@
if (doAnimation) {
if (DEBUG_VISIBILITY) Slog.v(TAG, "doAnimation: mPolicyVisibility="
+ mPolicyVisibility + " mAnimation=" + mWinAnimator.mAnimation);
- if (!mService.okToAnimate()) {
+ if (!mToken.okToAnimate()) {
doAnimation = false;
} else if (mPolicyVisibility && mWinAnimator.mAnimation == null) {
// Check for the case where we are currently visible and
@@ -2501,7 +2501,7 @@
boolean hideLw(boolean doAnimation, boolean requestAnim) {
if (doAnimation) {
- if (!mService.okToAnimate()) {
+ if (!mToken.okToAnimate()) {
doAnimation = false;
}
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 86265c29..053ee97 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -369,7 +369,7 @@
// we just started or just stopped animating by comparing mWasAnimating with isAnimationSet().
mWasAnimating = mAnimating;
final DisplayContent displayContent = mWin.getDisplayContent();
- if (displayContent != null && mService.okToAnimate()) {
+ if (mWin.mToken.okToAnimate()) {
// We will run animations as long as the display isn't frozen.
if (mWin.isDrawnLw() && mAnimation != null) {
@@ -1812,7 +1812,7 @@
// artifacts when we unfreeze the display if some different animation
// is running.
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "WSA#applyAnimationLocked");
- if (mService.okToAnimate()) {
+ if (mWin.mToken.okToAnimate()) {
int anim = mPolicy.selectAnimationLw(mWin, transit);
int attr = -1;
Animation a = null;
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index e3033c9..48d1618 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -288,4 +288,12 @@
String getName() {
return toString();
}
+
+ boolean okToDisplay() {
+ return mDisplayContent != null && mDisplayContent.okToDisplay();
+ }
+
+ boolean okToAnimate() {
+ return mDisplayContent != null && mDisplayContent.okToAnimate();
+ }
}
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index 801479b..65bf330 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -46,6 +46,7 @@
import android.app.NotificationManager;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.graphics.Color;
import android.media.AudioAttributes;
import android.net.Uri;
@@ -78,6 +79,7 @@
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -127,6 +129,8 @@
when(mPm.getPackageUidAsUser(eq(UPDATED_PKG), anyInt())).thenReturn(UID2);
when(mContext.getResources()).thenReturn(
InstrumentationRegistry.getContext().getResources());
+ when(mContext.getContentResolver()).thenReturn(
+ InstrumentationRegistry.getContext().getContentResolver());
when(mContext.getPackageManager()).thenReturn(mPm);
when(mContext.getApplicationInfo()).thenReturn(legacy);
// most tests assume badging is enabled
@@ -1366,4 +1370,22 @@
assertFalse(mHelper.badgingEnabled(USER));
assertTrue(mHelper.badgingEnabled(USER2));
}
+
+ @Test
+ public void testOnLocaleChanged_updatesDefaultChannels() throws Exception {
+ String newLabel = "bananas!";
+ final NotificationChannel defaultChannel = mHelper.getNotificationChannel(PKG, UID,
+ NotificationChannel.DEFAULT_CHANNEL_ID, false);
+ assertFalse(newLabel.equals(defaultChannel.getName()));
+
+ Resources res = mock(Resources.class);
+ when(mContext.getResources()).thenReturn(res);
+ when(res.getString(com.android.internal.R.string.default_notification_channel_label))
+ .thenReturn(newLabel);
+
+ mHelper.onLocaleChanged(mContext, USER.getIdentifier());
+
+ assertEquals(newLabel, mHelper.getNotificationChannel(PKG, UID,
+ NotificationChannel.DEFAULT_CHANNEL_ID, false).getName());
+ }
}
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index 507b483..19396d4 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -29,7 +29,8 @@
LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/aidl
-LOCAL_SRC_FILES += aidl/com/android/servicestests/aidl/INetworkStateObserver.aidl
+LOCAL_SRC_FILES += aidl/com/android/servicestests/aidl/INetworkStateObserver.aidl \
+ aidl/com/android/servicestests/aidl/ICmdReceiverService.aidl
LOCAL_JAVA_LIBRARIES := android.test.mock legacy-android-test
@@ -61,3 +62,5 @@
LOCAL_STATIC_JAVA_LIBRARIES += ub-uiautomator
include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under, $(LOCAL_PATH))
\ No newline at end of file
diff --git a/services/tests/servicestests/AndroidTest.xml b/services/tests/servicestests/AndroidTest.xml
index 63f3b75..6a9983e 100644
--- a/services/tests/servicestests/AndroidTest.xml
+++ b/services/tests/servicestests/AndroidTest.xml
@@ -16,6 +16,7 @@
<configuration description="Runs Frameworks Services Tests.">
<target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
<option name="test-file-name" value="FrameworksServicesTests.apk" />
+ <option name="test-file-name" value="ConnTestApp.apk" />
</target_preparer>
<option name="test-suite-tag" value="apct" />
diff --git a/services/tests/servicestests/aidl/Android.mk b/services/tests/servicestests/aidl/Android.mk
index 0c9b839..166da1d 100644
--- a/services/tests/servicestests/aidl/Android.mk
+++ b/services/tests/servicestests/aidl/Android.mk
@@ -18,6 +18,7 @@
LOCAL_MODULE_TAGS := tests
LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := \
- com/android/servicestests/aidl/INetworkStateObserver.aidl
+ com/android/servicestests/aidl/INetworkStateObserver.aidl \
+ com/android/servicestests/aidl/ICmdReceiverService.aidl
LOCAL_MODULE := servicestests-aidl
include $(BUILD_STATIC_JAVA_LIBRARY)
\ No newline at end of file
diff --git a/services/tests/servicestests/aidl/com/android/servicestests/aidl/ICmdReceiverService.aidl b/services/tests/servicestests/aidl/com/android/servicestests/aidl/ICmdReceiverService.aidl
new file mode 100644
index 0000000..d964504
--- /dev/null
+++ b/services/tests/servicestests/aidl/com/android/servicestests/aidl/ICmdReceiverService.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2017 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.servicestests.aidl;
+
+interface ICmdReceiverService {
+ void finishActivity();
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/res/raw/conntestapp b/services/tests/servicestests/res/raw/conntestapp
deleted file mode 100644
index e993164..0000000
--- a/services/tests/servicestests/res/raw/conntestapp
+++ /dev/null
Binary files differ
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
index 48464e5..ba22159 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
@@ -78,7 +78,7 @@
service.mStackSupervisor.inResumeTopActivity = true;
testStack.mResumedActivity = activityRecord;
- final boolean waiting = testStack.checkReadyForSleepLocked();
+ final boolean waiting = testStack.goToSleepIfPossible(false);
// Ensure we report not being ready for sleep.
assertTrue(waiting);
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index 04b5bde..4ad92c7 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -218,6 +218,12 @@
return createTestStack(stackId, createOnTop);
}
+
+ // Always keep things awake
+ @Override
+ boolean hasAwakeDisplay() {
+ return true;
+ }
}
private static WindowManagerService prepareMockWindowManager() {
diff --git a/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java b/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
index 5b4c10f..7f48b8e 100644
--- a/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
@@ -16,48 +16,37 @@
package com.android.server.net;
-import static android.util.DebugUtils.valueToString;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import com.android.frameworks.servicestests.R;
+import com.android.servicestests.aidl.ICmdReceiverService;
import com.android.servicestests.aidl.INetworkStateObserver;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.IntentSender;
-import android.content.pm.IPackageDeleteObserver;
-import android.content.pm.PackageInstaller;
+import android.content.ServiceConnection;
import android.content.pm.PackageManager;
-import android.net.Uri;
import android.os.BatteryManager;
import android.os.Bundle;
-import android.os.RemoteException;
+import android.os.IBinder;
import android.os.SystemClock;
+import android.provider.Settings;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.UiDevice;
import android.util.Log;
-import libcore.io.IoUtils;
-
import org.junit.AfterClass;
import org.junit.BeforeClass;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -76,62 +65,118 @@
* Run: adb shell am instrument -e class com.android.server.net.ConnOnActivityStartTest -w \
* com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
*/
-@Ignore
@LargeTest
@RunWith(AndroidJUnit4.class)
public class ConnOnActivityStartTest {
private static final String TAG = ConnOnActivityStartTest.class.getSimpleName();
- private static final String ACTION_INSTALL_COMPLETE = "com.android.server.net.INSTALL_COMPLETE";
-
- private static final String TEST_APP_URI =
- "android.resource://com.android.frameworks.servicestests/raw/conntestapp";
private static final String TEST_PKG = "com.android.servicestests.apps.conntestapp";
private static final String TEST_ACTIVITY_CLASS = TEST_PKG + ".ConnTestActivity";
-
- private static final String ACTION_FINISH_ACTIVITY = TEST_PKG + ".FINISH";
+ private static final String TEST_SERVICE_CLASS = TEST_PKG + ".CmdReceiverService";
private static final String EXTRA_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer";
private static final long BATTERY_OFF_TIMEOUT_MS = 2000; // 2 sec
private static final long BATTERY_OFF_CHECK_INTERVAL_MS = 200; // 0.2 sec
- private static final long WAIT_FOR_INSTALL_TIMEOUT_MS = 2000; // 2 sec
-
private static final long NETWORK_CHECK_TIMEOUT_MS = 4000; // 4 sec
private static final long SCREEN_ON_DELAY_MS = 500; // 0.5 sec
+ private static final long BIND_SERVICE_TIMEOUT_SEC = 4;
+
private static final int REPEAT_TEST_COUNT = 5;
+ private static final String KEY_PAROLE_DURATION = "parole_duration";
+ private static final String DESIRED_PAROLE_DURATION = "0";
+
private static Context mContext;
private static UiDevice mUiDevice;
private static int mTestPkgUid;
private static BatteryManager mBatteryManager;
+ private static boolean mAppIdleConstsUpdated;
+ private static String mOriginalAppIdleConsts;
+
+ private static ServiceConnection mServiceConnection;
+ private static ICmdReceiverService mCmdReceiverService;
+
@BeforeClass
public static void setUpOnce() throws Exception {
mContext = InstrumentationRegistry.getContext();
mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
- installAppAndAssertInstalled();
+ setDesiredParoleDuration();
mContext.getPackageManager().setApplicationEnabledSetting(TEST_PKG,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
mTestPkgUid = mContext.getPackageManager().getPackageUid(TEST_PKG, 0);
mBatteryManager = (BatteryManager) mContext.getSystemService(Context.BATTERY_SERVICE);
+ bindService();
}
@AfterClass
public static void tearDownOnce() {
- mContext.getPackageManager().deletePackage(TEST_PKG,
- new IPackageDeleteObserver.Stub() {
- @Override
- public void packageDeleted(String packageName, int returnCode)
- throws RemoteException {
- Log.e(TAG, packageName + " deleted, returnCode: " + returnCode);
- }
- }, 0);
+ if (mAppIdleConstsUpdated) {
+ Settings.Global.putString(mContext.getContentResolver(),
+ Settings.Global.APP_IDLE_CONSTANTS, mOriginalAppIdleConsts);
+ }
+ unbindService();
+ }
+
+ private static void bindService() throws Exception {
+ final CountDownLatch bindLatch = new CountDownLatch(1);
+ mServiceConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ Log.i(TAG, "Service connected");
+ mCmdReceiverService = ICmdReceiverService.Stub.asInterface(service);
+ bindLatch.countDown();
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ Log.i(TAG, "Service disconnected");
+ }
+ };
+ final Intent intent = new Intent()
+ .setComponent(new ComponentName(TEST_PKG, TEST_SERVICE_CLASS));
+ // Needs to use BIND_ALLOW_OOM_MANAGEMENT and BIND_NOT_FOREGROUND so that the test app
+ // does not run in the same process state as this app.
+ mContext.bindService(intent, mServiceConnection,
+ Context.BIND_AUTO_CREATE
+ | Context.BIND_ALLOW_OOM_MANAGEMENT
+ | Context.BIND_NOT_FOREGROUND);
+ if (!bindLatch.await(BIND_SERVICE_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ fail("Timed out waiting for the service to bind in " + mTestPkgUid);
+ }
+ }
+
+ private static void unbindService() {
+ if (mCmdReceiverService != null) {
+ mContext.unbindService(mServiceConnection);
+ }
+ }
+
+ private static void setDesiredParoleDuration() {
+ mOriginalAppIdleConsts = Settings.Global.getString(mContext.getContentResolver(),
+ Settings.Global.APP_IDLE_CONSTANTS);
+ String newAppIdleConstants;
+ final String newConstant = KEY_PAROLE_DURATION + "=" + DESIRED_PAROLE_DURATION;
+ if (mOriginalAppIdleConsts == null || "null".equals(mOriginalAppIdleConsts)) {
+ // app_idle_constants is initially empty, so just assign the desired value.
+ newAppIdleConstants = newConstant;
+ } else if (mOriginalAppIdleConsts.contains(KEY_PAROLE_DURATION)) {
+ // app_idle_constants contains parole_duration, so replace it with the desired value.
+ newAppIdleConstants = mOriginalAppIdleConsts.replaceAll(
+ KEY_PAROLE_DURATION + "=\\d+", newConstant);
+ } else {
+ // app_idle_constants didn't have parole_duration, so append the desired value.
+ newAppIdleConstants = mOriginalAppIdleConsts + "," + newConstant;
+ }
+ Settings.Global.putString(mContext.getContentResolver(),
+ Settings.Global.APP_IDLE_CONSTANTS, newAppIdleConstants);
+ mAppIdleConstsUpdated = true;
}
@Test
@@ -174,6 +219,7 @@
startActivityAndCheckNetworkAccess();
} finally {
turnBatteryOn();
+ finishActivity();
setAppIdle(false);
}
}
@@ -195,9 +241,9 @@
turnScreenOn();
SystemClock.sleep(SCREEN_ON_DELAY_MS);
startActivityAndCheckNetworkAccess();
- Log.d(TAG, testName + " end #" + i);
} finally {
finishActivity();
+ Log.d(TAG, testName + " end #" + i);
}
}
}
@@ -348,74 +394,7 @@
}
}
- private void finishActivity() {
- final Intent finishIntent = new Intent(ACTION_FINISH_ACTIVITY)
- .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- mContext.sendBroadcast(finishIntent);
- }
- private static void installAppAndAssertInstalled() throws Exception {
- final CountDownLatch latch = new CountDownLatch(1);
- final int[] result = {PackageInstaller.STATUS_SUCCESS};
- final BroadcastReceiver installStatusReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String pkgName = intent.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME);
- if (!TEST_PKG.equals(pkgName)) {
- return;
- }
- result[0] = intent.getIntExtra(PackageInstaller.EXTRA_STATUS,
- PackageInstaller.STATUS_FAILURE);
- latch.countDown();
- }
- };
- mContext.registerReceiver(installStatusReceiver, new IntentFilter(ACTION_INSTALL_COMPLETE));
- try {
- installApp();
- if (latch.await(WAIT_FOR_INSTALL_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
- if (result[0] != PackageInstaller.STATUS_SUCCESS) {
- fail("Couldn't install test app, result: "
- + valueToString(PackageInstaller.class, "STATUS_", result[0]));
- }
- } else {
- fail("Timed out waiting for the test app to install");
- }
- } finally {
- mContext.unregisterReceiver(installStatusReceiver);
- }
- }
-
- private static void installApp() throws Exception {
- final Uri packageUri = Uri.parse(TEST_APP_URI);
- final InputStream in = mContext.getContentResolver().openInputStream(packageUri);
-
- final PackageInstaller packageInstaller
- = mContext.getPackageManager().getPackageInstaller();
- final PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
- PackageInstaller.SessionParams.MODE_FULL_INSTALL);
- params.setAppPackageName(TEST_PKG);
-
- final int sessionId = packageInstaller.createSession(params);
- final PackageInstaller.Session session = packageInstaller.openSession(sessionId);
-
- OutputStream out = null;
- try {
- out = session.openWrite(TAG, 0, -1);
- final byte[] buffer = new byte[65536];
- int c;
- while ((c = in.read(buffer)) != -1) {
- out.write(buffer, 0, c);
- }
- session.fsync(out);
- } finally {
- IoUtils.closeQuietly(in);
- IoUtils.closeQuietly(out);
- }
- session.commit(createIntentSender(mContext, sessionId));
- }
-
- private static IntentSender createIntentSender(Context context, int sessionId) {
- PendingIntent pendingIntent = PendingIntent.getBroadcast(
- context, sessionId, new Intent(ACTION_INSTALL_COMPLETE), 0);
- return pendingIntent.getIntentSender();
+ private void finishActivity() throws Exception {
+ mCmdReceiverService.finishActivity();
}
}
\ No newline at end of file
diff --git a/services/tests/servicestests/test-apps/Android.mk b/services/tests/servicestests/test-apps/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/services/tests/servicestests/test-apps/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/services/tests/servicestests/test-apps/ConnTestApp/Android.mk b/services/tests/servicestests/test-apps/ConnTestApp/Android.mk
index 030a709..fbfa28a 100644
--- a/services/tests/servicestests/test-apps/ConnTestApp/Android.mk
+++ b/services/tests/servicestests/test-apps/ConnTestApp/Android.mk
@@ -18,6 +18,8 @@
LOCAL_MODULE_TAGS := tests
+LOCAL_COMPATIBILITY_SUITE := device-tests
+
LOCAL_STATIC_JAVA_LIBRARIES := servicestests-aidl
LOCAL_SRC_FILES := $(call all-subdir-java-files)
diff --git a/services/tests/servicestests/test-apps/ConnTestApp/AndroidManifest.xml b/services/tests/servicestests/test-apps/ConnTestApp/AndroidManifest.xml
index 6671410..909e9bb 100644
--- a/services/tests/servicestests/test-apps/ConnTestApp/AndroidManifest.xml
+++ b/services/tests/servicestests/test-apps/ConnTestApp/AndroidManifest.xml
@@ -24,6 +24,8 @@
<application>
<activity android:name=".ConnTestActivity"
android:exported="true" />
+ <service android:name=".CmdReceiverService"
+ android:exported="true" />
</application>
</manifest>
\ No newline at end of file
diff --git a/services/tests/servicestests/test-apps/ConnTestApp/src/com/android/servicestests/apps/conntestapp/CmdReceiverService.java b/services/tests/servicestests/test-apps/ConnTestApp/src/com/android/servicestests/apps/conntestapp/CmdReceiverService.java
new file mode 100644
index 0000000..6130f3a
--- /dev/null
+++ b/services/tests/servicestests/test-apps/ConnTestApp/src/com/android/servicestests/apps/conntestapp/CmdReceiverService.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2017 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.servicestests.apps.conntestapp;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+import com.android.servicestests.aidl.ICmdReceiverService;
+
+public class CmdReceiverService extends Service {
+ private ICmdReceiverService.Stub mBinder = new ICmdReceiverService.Stub() {
+ @Override
+ public void finishActivity() {
+ ConnTestActivity.finishSelf();
+ }
+ };
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/test-apps/ConnTestApp/src/com/android/servicestests/apps/conntestapp/ConnTestActivity.java b/services/tests/servicestests/test-apps/ConnTestApp/src/com/android/servicestests/apps/conntestapp/ConnTestActivity.java
index c5c7add..b26cc7fd 100644
--- a/services/tests/servicestests/test-apps/ConnTestApp/src/com/android/servicestests/apps/conntestapp/ConnTestActivity.java
+++ b/services/tests/servicestests/test-apps/ConnTestApp/src/com/android/servicestests/apps/conntestapp/ConnTestActivity.java
@@ -30,6 +30,7 @@
import android.os.ServiceManager;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
import com.android.servicestests.aidl.INetworkStateObserver;
public class ConnTestActivity extends Activity {
@@ -39,17 +40,26 @@
private static final String ACTION_FINISH_ACTIVITY = TEST_PKG + ".FINISH";
private static final String EXTRA_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer";
+ private static final Object INSTANCE_LOCK = new Object();
+ @GuardedBy("instanceLock")
+ private static Activity sInstance;
+
private BroadcastReceiver finishCommandReceiver = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ synchronized (INSTANCE_LOCK) {
+ sInstance = this;
+ }
+ Log.i(TAG, "onCreate called");
notifyNetworkStateObserver();
finishCommandReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ Log.i(TAG, "finish command received");
ConnTestActivity.this.finish();
}
};
@@ -57,13 +67,37 @@
}
@Override
+ public void onResume() {
+ super.onResume();
+ Log.i(TAG, "onResume called");
+ }
+
+ @Override
public void onStop() {
+ Log.i(TAG, "onStop called");
if (finishCommandReceiver != null) {
unregisterReceiver(finishCommandReceiver);
}
super.onStop();
}
+ @Override
+ public void finish() {
+ synchronized (INSTANCE_LOCK) {
+ sInstance = null;
+ }
+ Log.i(TAG, "finish called");
+ super.finish();
+ }
+
+ public static void finishSelf() {
+ synchronized (INSTANCE_LOCK) {
+ if (sInstance != null) {
+ sInstance.finish();
+ }
+ }
+ }
+
private void notifyNetworkStateObserver() {
if (getIntent() == null) {
return;
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index c1289d3..e13bd61 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -1089,12 +1089,17 @@
* @return A string containing text sent by the remote user, or {@code null} if the
* conversation has been terminated or if there was an error while reading.
*/
- public String read() throws IOException {
- int numRead = mReceiveStream.read(mReadBuffer, 0, READ_BUFFER_SIZE);
- if (numRead < 0) {
+ public String read() {
+ try {
+ int numRead = mReceiveStream.read(mReadBuffer, 0, READ_BUFFER_SIZE);
+ if (numRead < 0) {
+ return null;
+ }
+ return new String(mReadBuffer, 0, numRead);
+ } catch (IOException e) {
+ Log.w(this, "Exception encountered when reading from InputStreamReader: %s", e);
return null;
}
- return new String(mReadBuffer, 0, numRead);
}
/**
@@ -1105,7 +1110,11 @@
*/
public String readImmediately() throws IOException {
if (mReceiveStream.ready()) {
- return read();
+ int numRead = mReceiveStream.read(mReadBuffer, 0, READ_BUFFER_SIZE);
+ if (numRead < 0) {
+ return null;
+ }
+ return new String(mReadBuffer, 0, numRead);
} else {
return null;
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 3a34d8f..81353df 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -567,20 +567,27 @@
"carrier_data_call_retry_config_strings";
/**
- * Delay between trying APN from the pool
+ * Delay in milliseconds between trying APN from the pool
* @hide
*/
public static final String KEY_CARRIER_DATA_CALL_APN_DELAY_DEFAULT_LONG =
"carrier_data_call_apn_delay_default_long";
/**
- * Faster delay between trying APN from the pool
+ * Faster delay in milliseconds between trying APN from the pool
* @hide
*/
public static final String KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG =
"carrier_data_call_apn_delay_faster_long";
/**
+ * Delay in milliseconds for retrying APN after disconnect
+ * @hide
+ */
+ public static final String KEY_CARRIER_DATA_CALL_APN_RETRY_AFTER_DISCONNECT_LONG =
+ "carrier_data_call_apn_retry_after_disconnect_long";
+
+ /**
* Data call setup permanent failure causes by the carrier
*/
public static final String KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS =
@@ -768,7 +775,6 @@
* Determines whether High Definition audio property is displayed in the dialer UI.
* If {@code false}, remove the HD audio property from the connection so that HD audio related
* UI is not displayed. If {@code true}, keep HD audio property as it is configured.
- * @hide
*/
public static final String KEY_DISPLAY_HD_AUDIO_PROPERTY_BOOL =
"display_hd_audio_property_bool";
@@ -1646,6 +1652,7 @@
"others:max_retries=3, 5000, 5000, 5000"});
sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_DEFAULT_LONG, 20000);
sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG, 3000);
+ sDefaults.putLong(KEY_CARRIER_DATA_CALL_APN_RETRY_AFTER_DISCONNECT_LONG, 10000);
sDefaults.putString(KEY_CARRIER_ERI_FILE_NAME_STRING, "eri.xml");
sDefaults.putInt(KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT, 7200);
sDefaults.putStringArray(KEY_CARRIER_METERED_APN_TYPES_STRINGS,
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 8304d84..a13af5f 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -154,6 +154,14 @@
"android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_RESOLUTION_CALLBACK_INTENT";
/**
+ * Key for an extra set on the {@link #ACTION_PROVISION_EMBEDDED_SUBSCRIPTION} intent for
+ * whether the user choses to use eUICC to set up network in SUW.
+ * @hide
+ */
+ public static final String EXTRA_FORCE_PROVISION =
+ "android.telephony.euicc.extra.FORCE_PROVISION";
+
+ /**
* Optional meta-data attribute for a carrier app providing an icon to use to represent the
* carrier. If not provided, the app's launcher icon will be used as a fallback.
*/
diff --git a/tests/Internal/src/android/app/WallpaperColorsTest.java b/tests/Internal/src/android/app/WallpaperColorsTest.java
index fb529b9..881f628 100644
--- a/tests/Internal/src/android/app/WallpaperColorsTest.java
+++ b/tests/Internal/src/android/app/WallpaperColorsTest.java
@@ -36,12 +36,12 @@
final Color color = Color.valueOf(Color.WHITE);
// Default should not support dark text!
WallpaperColors colors = new WallpaperColors(color, null, null, 0);
- Assert.assertTrue("Default behavior is not to support dark text",
+ Assert.assertTrue("Default behavior is not to support dark text.",
(colors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) == 0);
// Override it
colors = new WallpaperColors(color, null, null, WallpaperColors.HINT_SUPPORTS_DARK_TEXT);
- Assert.assertFalse("Forcing dark text support doesn't work",
+ Assert.assertFalse("Forcing dark text support doesn't work.",
(colors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) == 0);
}
@@ -57,15 +57,18 @@
int hints = WallpaperColors.fromBitmap(image).getColorHints();
boolean supportsDarkText = (hints & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) != 0;
boolean supportsDarkTheme = (hints & WallpaperColors.HINT_SUPPORTS_DARK_THEME) != 0;
- Assert.assertTrue("White surface should support dark text", supportsDarkText);
- Assert.assertFalse("White surface shouldn't support dark theme", supportsDarkTheme);
+ boolean fromBitmap = (hints & WallpaperColors.HINT_FROM_BITMAP) != 0;
+ Assert.assertTrue("White surface should support dark text.", supportsDarkText);
+ Assert.assertFalse("White surface shouldn't support dark theme.", supportsDarkTheme);
+ Assert.assertTrue("From bitmap should be true if object was created "
+ + "using WallpaperColors#fromBitmap.", fromBitmap);
canvas.drawColor(Color.BLACK);
hints = WallpaperColors.fromBitmap(image).getColorHints();
supportsDarkText = (hints & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) != 0;
supportsDarkTheme = (hints & WallpaperColors.HINT_SUPPORTS_DARK_THEME) != 0;
- Assert.assertFalse("Black surface shouldn't support dark text", supportsDarkText);
- Assert.assertTrue("Black surface should support dark theme", supportsDarkTheme);
+ Assert.assertFalse("Black surface shouldn't support dark text.", supportsDarkText);
+ Assert.assertTrue("Black surface should support dark theme.", supportsDarkTheme);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
@@ -75,7 +78,12 @@
supportsDarkText = (WallpaperColors.fromBitmap(image)
.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT) != 0;
Assert.assertFalse("Light surface shouldn't support dark text "
- + "when it contains dark pixels", supportsDarkText);
+ + "when it contains dark pixels.", supportsDarkText);
+
+ WallpaperColors colors = new WallpaperColors(Color.valueOf(Color.GREEN), null, null);
+ fromBitmap = (colors.getColorHints() & WallpaperColors.HINT_FROM_BITMAP) != 0;
+ Assert.assertFalse("Object created from public constructor should not contain "
+ + "HINT_FROM_BITMAP.", fromBitmap);
}
/**
diff --git a/tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java b/tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java
index 6dc9ba7..d46fff4 100644
--- a/tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java
+++ b/tests/Internal/src/com/android/internal/colorextraction/types/TonalTest.java
@@ -99,20 +99,39 @@
}
@Test
- public void tonal_excludeBlacklistedColor() {
+ public void tonal_blacklistTest() {
// Make sure that palette generation will fail.
- Tonal tonal = new Tonal(InstrumentationRegistry.getContext());
+ final Tonal tonal = new Tonal(InstrumentationRegistry.getContext());
// Creating a WallpaperColors object that contains *only* blacklisted colors.
- float[] hsl = tonal.getBlacklistedColors().get(0).getCenter();
- WallpaperColors colors = new WallpaperColors(Color.valueOf(ColorUtils.HSLToColor(hsl)),
- null, null, 0);
+ final float[] hsl = tonal.getBlacklistedColors().get(0).getCenter();
+ final int blacklistedColor = ColorUtils.HSLToColor(hsl);
+ WallpaperColors colorsFromBitmap = new WallpaperColors(Color.valueOf(blacklistedColor),
+ null, null, WallpaperColors.HINT_FROM_BITMAP);
// Make sure that palette generation will fail
- GradientColors normal = new GradientColors();
- tonal.extractInto(colors, normal, new GradientColors(),
+ final GradientColors normal = new GradientColors();
+ tonal.extractInto(colorsFromBitmap, normal, new GradientColors(),
new GradientColors());
assertTrue("Cannot generate a tonal palette from blacklisted colors.",
normal.getMainColor() == Tonal.MAIN_COLOR_DARK);
}
+
+ @Test
+ public void tonal_ignoreBlacklistTest() {
+ final Tonal tonal = new Tonal(InstrumentationRegistry.getContext());
+
+ // Creating a WallpaperColors object that contains *only* blacklisted colors.
+ final float[] hsl = tonal.getBlacklistedColors().get(0).getCenter();
+ final int blacklistedColor = ColorUtils.HSLToColor(hsl);
+ WallpaperColors colors = new WallpaperColors(Color.valueOf(blacklistedColor),
+ null, null);
+
+ // Blacklist should be ignored when HINT_FROM_BITMAP isn't present.
+ final GradientColors normal = new GradientColors();
+ tonal.extractInto(colors, normal, new GradientColors(),
+ new GradientColors());
+ assertTrue("Blacklist should never be used on WallpaperColors generated using "
+ + "default constructor.", normal.getMainColor() == blacklistedColor);
+ }
}
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index f0b3724..296cb76 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -346,7 +346,7 @@
// Apps that opt out explicitly are not supported
appInfo.targetSdkVersion = VERSION_CODES.CUR_DEVELOPMENT;
Bundle metaData = new Bundle();
- metaData.putBoolean(VpnService.METADATA_SUPPORTS_ALWAYS_ON, false);
+ metaData.putBoolean(VpnService.SERVICE_META_DATA_SUPPORTS_ALWAYS_ON, false);
svcInfo.metaData = metaData;
assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0]));
}
diff --git a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java b/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
index c4965a0..983e04d 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
@@ -85,6 +85,8 @@
ArgumentCaptor.forClass(ArrayList.class);
private final ArgumentCaptor<ITetheringStatsProvider.Stub> mTetherStatsProviderCaptor =
ArgumentCaptor.forClass(ITetheringStatsProvider.Stub.class);
+ private final ArgumentCaptor<OffloadHardwareInterface.ControlCallback> mControlCallbackCaptor =
+ ArgumentCaptor.forClass(OffloadHardwareInterface.ControlCallback.class);
private MockContentResolver mContentResolver;
@Before public void setUp() {
@@ -103,7 +105,7 @@
private void setupFunctioningHardwareInterface() {
when(mHardware.initOffloadConfig()).thenReturn(true);
- when(mHardware.initOffloadControl(any(OffloadHardwareInterface.ControlCallback.class)))
+ when(mHardware.initOffloadControl(mControlCallbackCaptor.capture()))
.thenReturn(true);
when(mHardware.getForwardedStats(any())).thenReturn(new ForwardedStats());
}
@@ -489,4 +491,17 @@
waitForIdle();
inOrder.verify(mHardware).stopOffloadControl();
}
+
+ @Test
+ public void testDataLimitCallback() throws Exception {
+ setupFunctioningHardwareInterface();
+ enableOffload();
+
+ final OffloadController offload = makeOffloadController();
+ offload.start();
+
+ OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue();
+ callback.onStoppedLimitReached();
+ verify(mNMService, times(1)).tetherLimitReached(mTetherStatsProviderCaptor.getValue());
+ }
}