Merge "Make public getFragments() and onGetLayoutInflater() methods" into oc-dev
diff --git a/api/current.txt b/api/current.txt
index b45e64b..788c1d4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3673,7 +3673,7 @@
method public void onLowMemory();
method public boolean onMenuItemSelected(int, android.view.MenuItem);
method public boolean onMenuOpened(int, android.view.Menu);
- method public void onMovedToDisplay(int);
+ method public void onMovedToDisplay(int, android.content.res.Configuration);
method public void onMultiWindowModeChanged(boolean);
method public boolean onNavigateUp();
method public boolean onNavigateUpFromChild(android.app.Activity);
@@ -12697,7 +12697,7 @@
enum_constant public static final android.graphics.Canvas.VertexMode TRIANGLE_STRIP;
}
- public class Color {
+ public final class Color {
ctor public Color();
method public static int HSVToColor(float[]);
method public static int HSVToColor(int, float[]);
@@ -12722,6 +12722,7 @@
method public float getComponent(int);
method public int getComponentCount();
method public float[] getComponents();
+ method public float[] getComponents(float[]);
method public android.graphics.ColorSpace.Model getModel();
method public float green();
method public static float green(long);
@@ -45490,7 +45491,7 @@
method public boolean onKeyUp(int, android.view.KeyEvent);
method protected void onLayout(boolean, int, int, int, int);
method protected void onMeasure(int, int);
- method public void onMovedToDisplay(int);
+ method public void onMovedToDisplay(int, android.content.res.Configuration);
method protected void onOverScrolled(int, int, boolean, boolean);
method public void onPointerCaptureChange(boolean);
method public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
diff --git a/api/system-current.txt b/api/system-current.txt
index 6efac13..c07b928 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3799,7 +3799,7 @@
method public void onLowMemory();
method public boolean onMenuItemSelected(int, android.view.MenuItem);
method public boolean onMenuOpened(int, android.view.Menu);
- method public void onMovedToDisplay(int);
+ method public void onMovedToDisplay(int, android.content.res.Configuration);
method public void onMultiWindowModeChanged(boolean);
method public boolean onNavigateUp();
method public boolean onNavigateUpFromChild(android.app.Activity);
@@ -11174,6 +11174,7 @@
method public abstract byte[] getInstantAppCookie();
method public abstract int getInstantAppCookieMaxSize();
method public abstract android.graphics.drawable.Drawable getInstantAppIcon(java.lang.String);
+ method public abstract android.content.ComponentName getInstantAppResolverSettingsComponent();
method public abstract java.util.List<android.content.pm.InstantAppInfo> getInstantApps();
method public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(java.lang.String);
@@ -11423,6 +11424,7 @@
field public static final int MATCH_DIRECT_BOOT_UNAWARE = 262144; // 0x40000
field public static final int MATCH_DISABLED_COMPONENTS = 512; // 0x200
field public static final int MATCH_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
+ field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000
field public static final int MATCH_INSTANT = 8388608; // 0x800000
field public static final int MATCH_SYSTEM_ONLY = 1048576; // 0x100000
field public static final int MATCH_UNINSTALLED_PACKAGES = 8192; // 0x2000
@@ -13423,7 +13425,7 @@
enum_constant public static final android.graphics.Canvas.VertexMode TRIANGLE_STRIP;
}
- public class Color {
+ public final class Color {
ctor public Color();
method public static int HSVToColor(float[]);
method public static int HSVToColor(int, float[]);
@@ -13448,6 +13450,7 @@
method public float getComponent(int);
method public int getComponentCount();
method public float[] getComponents();
+ method public float[] getComponents(float[]);
method public android.graphics.ColorSpace.Model getModel();
method public float green();
method public static float green(long);
@@ -44216,6 +44219,7 @@
method public byte[] getInstantAppCookie();
method public int getInstantAppCookieMaxSize();
method public android.graphics.drawable.Drawable getInstantAppIcon(java.lang.String);
+ method public android.content.ComponentName getInstantAppResolverSettingsComponent();
method public java.util.List<android.content.pm.InstantAppInfo> getInstantApps();
method public android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(java.lang.String);
@@ -48944,7 +48948,7 @@
method public boolean onKeyUp(int, android.view.KeyEvent);
method protected void onLayout(boolean, int, int, int, int);
method protected void onMeasure(int, int);
- method public void onMovedToDisplay(int);
+ method public void onMovedToDisplay(int, android.content.res.Configuration);
method protected void onOverScrolled(int, int, boolean, boolean);
method public void onPointerCaptureChange(boolean);
method public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
diff --git a/api/test-current.txt b/api/test-current.txt
index 8589d4b..00bc3c2 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -3675,7 +3675,7 @@
method public void onLowMemory();
method public boolean onMenuItemSelected(int, android.view.MenuItem);
method public boolean onMenuOpened(int, android.view.Menu);
- method public void onMovedToDisplay(int);
+ method public void onMovedToDisplay(int, android.content.res.Configuration);
method public void onMultiWindowModeChanged(boolean);
method public boolean onNavigateUp();
method public boolean onNavigateUpFromChild(android.app.Activity);
@@ -12747,7 +12747,7 @@
enum_constant public static final android.graphics.Canvas.VertexMode TRIANGLE_STRIP;
}
- public class Color {
+ public final class Color {
ctor public Color();
method public static int HSVToColor(float[]);
method public static int HSVToColor(int, float[]);
@@ -12772,6 +12772,7 @@
method public float getComponent(int);
method public int getComponentCount();
method public float[] getComponents();
+ method public float[] getComponents(float[]);
method public android.graphics.ColorSpace.Model getModel();
method public float green();
method public static float green(long);
@@ -45865,7 +45866,7 @@
method public boolean onKeyUp(int, android.view.KeyEvent);
method protected void onLayout(boolean, int, int, int, int);
method protected void onMeasure(int, int);
- method public void onMovedToDisplay(int);
+ method public void onMovedToDisplay(int, android.content.res.Configuration);
method protected void onOverScrolled(int, int, boolean, boolean);
method public void onPointerCaptureChange(boolean);
method public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index fa1de03..bace226 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1990,27 +1990,32 @@
}
}
- void dispatchMovedToDisplay(int displayId) {
+ void dispatchMovedToDisplay(int displayId, Configuration config) {
updateDisplay(displayId);
- onMovedToDisplay(displayId);
+ onMovedToDisplay(displayId, config);
}
/**
* Called by the system when the activity is moved from one display to another without
* recreation. This means that this activity is declared to handle all changes to configuration
* that happened when it was switched to another display, so it wasn't destroyed and created
- * again. This call will be followed by {@link #onConfigurationChanged(Configuration)} if the
- * applied configuration actually changed.
+ * again.
+ *
+ * <p>This call will be followed by {@link #onConfigurationChanged(Configuration)} if the
+ * applied configuration actually changed. It is up to app developer to choose whether to handle
+ * the change in this method or in the following {@link #onConfigurationChanged(Configuration)}
+ * call.
*
* <p>Use this callback to track changes to the displays if some activity functionality relies
* on an association with some display properties.
*
* @param displayId The id of the display to which activity was moved.
+ * @param config Configuration of the activity resources on new display after move.
*
* @see #onConfigurationChanged(Configuration)
- * @see View#onMovedToDisplay(int)
+ * @see View#onMovedToDisplay(int, Configuration)
*/
- public void onMovedToDisplay(int displayId) {
+ public void onMovedToDisplay(int displayId, Configuration config) {
}
/**
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index b4e6bd5..b5d1fa8 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -808,11 +808,6 @@
public final void scheduleReceiver(Intent intent, ActivityInfo info,
CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,
boolean sync, int sendingUser, int processState) {
- // TODO: Debugging added for bug:36406078 . Remove when done
- if (Log.isLoggable("36406078", Log.DEBUG)) {
- Log.d(TAG, "scheduleReceiver");
- }
-
updateProcessState(processState, false);
ReceiverData r = new ReceiverData(intent, resultCode, data, extras,
sync, false, mAppThread.asBinder(), sendingUser);
@@ -899,11 +894,6 @@
CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
String buildSerial) {
- // TODO: Debugging added for bug:36406078 . Remove when done
- if (Log.isLoggable("36406078", Log.DEBUG)) {
- Log.d(TAG, "bindApplication: " + processName);
- }
-
if (services != null) {
// Setup the service cache in the ServiceManager
ServiceManager.initServiceCache(services);
@@ -3239,10 +3229,6 @@
if (receiver.getPendingResult() != null) {
data.finish();
}
- // TODO: Debugging added for bug:36406078 . Remove when done
- if (Log.isLoggable("36406078", Log.DEBUG)) {
- Log.d(TAG, "handleReceiver done");
- }
}
// Instantiate a BackupAgent and tell it that it's alive
@@ -4815,16 +4801,18 @@
* {@link ActivityClientRecord#overrideConfig}.
* @param displayId The id of the display where the Activity currently resides.
* @param movedToDifferentDisplay Indicates if the activity was moved to different display.
+ * @return {@link Configuration} instance sent to client, null if not sent.
*/
- private void performConfigurationChangedForActivity(ActivityClientRecord r,
+ private Configuration performConfigurationChangedForActivity(ActivityClientRecord r,
Configuration newBaseConfig, int displayId, boolean movedToDifferentDisplay) {
r.tmpConfig.setTo(newBaseConfig);
if (r.overrideConfig != null) {
r.tmpConfig.updateFrom(r.overrideConfig);
}
- performActivityConfigurationChanged(r.activity, r.tmpConfig, r.overrideConfig, displayId,
- movedToDifferentDisplay);
+ final Configuration reportedConfig = performActivityConfigurationChanged(r.activity,
+ r.tmpConfig, r.overrideConfig, displayId, movedToDifferentDisplay);
freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(r.tmpConfig));
+ return reportedConfig;
}
/**
@@ -4878,9 +4866,11 @@
* ActivityManager.
* @param displayId Id of the display where activity currently resides.
* @param movedToDifferentDisplay Indicates if the activity was moved to different display.
+ * @return Configuration sent to client, null if no changes and not moved to different display.
*/
- private void performActivityConfigurationChanged(Activity activity, Configuration newConfig,
- Configuration amOverrideConfig, int displayId, boolean movedToDifferentDisplay) {
+ private Configuration performActivityConfigurationChanged(Activity activity,
+ Configuration newConfig, Configuration amOverrideConfig, int displayId,
+ boolean movedToDifferentDisplay) {
if (activity == null) {
throw new IllegalArgumentException("No activity provided.");
}
@@ -4911,7 +4901,7 @@
}
if (!shouldChangeConfig && !movedToDifferentDisplay) {
// Nothing significant, don't proceed with updating and reporting.
- return;
+ return null;
}
// Propagate the configuration change to ResourcesManager and Activity.
@@ -4934,22 +4924,22 @@
activity.mConfigChangeFlags = 0;
activity.mCurrentConfig = new Configuration(newConfig);
+ // Apply the ContextThemeWrapper override if necessary.
+ // NOTE: Make sure the configurations are not modified, as they are treated as immutable
+ // in many places.
+ final Configuration configToReport = createNewConfigAndUpdateIfNotNull(newConfig,
+ contextThemeWrapperOverrideConfig);
+
if (!REPORT_TO_ACTIVITY) {
// Not configured to report to activity.
- return;
+ return configToReport;
}
if (movedToDifferentDisplay) {
- activity.dispatchMovedToDisplay(displayId);
+ activity.dispatchMovedToDisplay(displayId, configToReport);
}
if (shouldChangeConfig) {
- // Apply the ContextThemeWrapper override if necessary.
- // NOTE: Make sure the configurations are not modified, as they are treated as immutable
- // in many places.
- final Configuration configToReport = createNewConfigAndUpdateIfNotNull(
- newConfig, contextThemeWrapperOverrideConfig);
-
activity.mCalled = false;
activity.onConfigurationChanged(configToReport);
if (!activity.mCalled) {
@@ -4957,6 +4947,8 @@
" did not call through to super.onConfigurationChanged()");
}
}
+
+ return configToReport;
}
public final void applyConfigurationToResources(Configuration config) {
@@ -5129,10 +5121,10 @@
+ r.activityInfo.name + ", displayId=" + displayId
+ ", config=" + data.overrideConfig);
- performConfigurationChangedForActivity(r, mCompatConfiguration, displayId,
- true /* movedToDifferentDisplay */);
+ final Configuration reportedConfig = performConfigurationChangedForActivity(r,
+ mCompatConfiguration, displayId, true /* movedToDifferentDisplay */);
if (viewRoot != null) {
- viewRoot.onMovedToDisplay(displayId);
+ viewRoot.onMovedToDisplay(displayId, reportedConfig);
}
} else {
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle activity config changed: "
@@ -5142,7 +5134,7 @@
// Notify the ViewRootImpl instance about configuration changes. It may have initiated this
// update to make sure that resources are updated before updating itself.
if (viewRoot != null) {
- viewRoot.updateConfiguration();
+ viewRoot.updateConfiguration(displayId);
}
mSomeActivitiesChanged = true;
}
@@ -5778,10 +5770,6 @@
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
- // TODO: Debugging added for bug:36406078 . Remove when done
- if (Log.isLoggable("36406078", Log.DEBUG)) {
- Log.d(TAG, "handleBindApplication done");
- }
}
/*package*/ final void finishInstrumentation(int resultCode, Bundle results) {
diff --git a/core/java/android/app/ApplicationLoaders.java b/core/java/android/app/ApplicationLoaders.java
index ef2db4a..2062930 100644
--- a/core/java/android/app/ApplicationLoaders.java
+++ b/core/java/android/app/ApplicationLoaders.java
@@ -18,6 +18,7 @@
import android.os.Build;
import android.os.Trace;
+import android.text.TextUtils;
import android.util.ArrayMap;
import com.android.internal.os.PathClassLoaderFactory;
import dalvik.system.PathClassLoader;
@@ -29,8 +30,16 @@
}
ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled,
- String librarySearchPath, String libraryPermittedPath,
- ClassLoader parent) {
+ String librarySearchPath, String libraryPermittedPath,
+ ClassLoader parent) {
+ // For normal usage the cache key used is the same as the zip path.
+ return getClassLoader(zip, targetSdkVersion, isBundled, librarySearchPath,
+ libraryPermittedPath, parent, zip);
+ }
+
+ private ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled,
+ String librarySearchPath, String libraryPermittedPath,
+ ClassLoader parent, String cacheKey) {
/*
* This is the parent we use if they pass "null" in. In theory
* this should be the "system" class loader; in practice we
@@ -50,7 +59,7 @@
* new ClassLoader for the zip archive.
*/
if (parent == baseParent) {
- ClassLoader loader = mLoaders.get(zip);
+ ClassLoader loader = mLoaders.get(cacheKey);
if (loader != null) {
return loader;
}
@@ -71,7 +80,7 @@
setupVulkanLayerPath(pathClassloader, librarySearchPath);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- mLoaders.put(zip, pathClassloader);
+ mLoaders.put(cacheKey, pathClassloader);
return pathClassloader;
}
@@ -87,12 +96,16 @@
* by this class. This is used in the WebView zygote, where its presence in the cache speeds up
* startup and enables memory sharing.
*/
- public ClassLoader createAndCacheWebViewClassLoader(String packagePath, String libsPath) {
- // The correct paths are calculated by WebViewZygote in the system server and passed to
- // us here. We hardcode the other parameters: WebView always targets the current SDK,
- // does not need to use non-public system libraries, and uses the base classloader as its
- // parent to permit usage of the cache.
- return getClassLoader(packagePath, Build.VERSION.SDK_INT, false, libsPath, null, null);
+ public ClassLoader createAndCacheWebViewClassLoader(String packagePath, String libsPath,
+ String cacheKey) {
+ // The correct paths are calculated by WebViewZygote in the system server and passed to
+ // us here. We hardcode the other parameters: WebView always targets the current SDK,
+ // does not need to use non-public system libraries, and uses the base classloader as its
+ // parent to permit usage of the cache.
+ // The cache key is passed separately to enable the stub WebView to be cached under the
+ // stub's APK path, when the actual package path is the donor APK.
+ return getClassLoader(packagePath, Build.VERSION.SDK_INT, false, libsPath, null, null,
+ cacheKey);
}
private static native void setupVulkanLayerPath(ClassLoader classLoader, String librarySearchPath);
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 286f8570..461f9cc 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -2630,4 +2630,13 @@
throw e.rethrowAsRuntimeException();
}
}
+
+ @Override
+ public ComponentName getInstantAppResolverSettingsComponent() {
+ try {
+ return mPM.getInstantAppResolverSettingsComponent();
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index fb86791..7890a96 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1532,6 +1532,19 @@
= "android.intent.action.RESOLVE_EPHEMERAL_PACKAGE";
/**
+ * Activity Action: Launch ephemeral settings.
+ *
+ * <p class="note">
+ * This is a protected intent that can only be sent by the system.
+ * </p>
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_EPHEMERAL_RESOLVER_SETTINGS
+ = "android.intent.action.EPHEMERAL_RESOLVER_SETTINGS";
+
+ /**
* Used as a string extra field with {@link #ACTION_INSTALL_PACKAGE} to install a
* package. Specifies the installer package name; this package will receive the
* {@link #ACTION_APP_ERROR} intent.
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 59b022d..147df76 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -630,4 +630,6 @@
boolean canRequestPackageInstalls(String packageName, int userId);
void deletePreloadsFileCache();
+
+ ComponentName getInstantAppResolverSettingsComponent();
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 71db5d3..136c13b 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -153,6 +153,7 @@
MATCH_UNINSTALLED_PACKAGES,
MATCH_SYSTEM_ONLY,
MATCH_DEBUG_TRIAGED_MISSING,
+ MATCH_DISABLED_COMPONENTS,
MATCH_DISABLED_UNTIL_USED_COMPONENTS,
MATCH_INSTANT,
GET_DISABLED_UNTIL_USED_COMPONENTS,
@@ -431,6 +432,7 @@
* This will not return information on any unbundled update to system components.
* @hide
*/
+ @SystemApi
public static final int MATCH_FACTORY_ONLY = 0x00200000;
/**
@@ -3730,6 +3732,7 @@
*
* @param flags Additional option flags. Use any combination of
* {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES},
+ * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}
* {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES}
* to modify the data returned.
*
@@ -3743,6 +3746,7 @@
*
* @see #GET_META_DATA
* @see #GET_SHARED_LIBRARY_FILES
+ * @see #MATCH_DISABLED_COMPONENTS
* @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
* @see #MATCH_SYSTEM_ONLY
* @see #MATCH_UNINSTALLED_PACKAGES
@@ -3757,6 +3761,7 @@
*
* @param flags Additional option flags. Use any combination of
* {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES},
+ * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}
* {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES}
* to modify the data returned.
* @param userId The user for whom the installed applications are to be listed
@@ -3772,6 +3777,7 @@
*
* @see #GET_META_DATA
* @see #GET_SHARED_LIBRARY_FILES
+ * @see #MATCH_DISABLED_COMPONENTS
* @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS
* @see #MATCH_SYSTEM_ONLY
* @see #MATCH_UNINSTALLED_PACKAGES
@@ -6233,4 +6239,14 @@
* @see {@link android.provider.Settings#ACTION_MANAGE_EXTERNAL_SOURCES}
*/
public abstract boolean canRequestPackageInstalls();
+
+ /**
+ * Return the {@link ComponentName} of the activity providing Settings for the Instant App
+ * resolver.
+ *
+ * @see {@link android.content.intent#ACTION_EPHEMERAL_RESOLVER_SETTINGS}
+ * @hide
+ */
+ @SystemApi
+ public abstract ComponentName getInstantAppResolverSettingsComponent();
}
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 6272822..370af17 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -172,6 +172,7 @@
* @param packageName The package name.
* @param userId The user for which to check.
* @return Whether was launched.
+ * @throws IllegalArgumentException if the package is not found
*/
public abstract boolean wasPackageEverLaunched(String packageName, int userId);
@@ -241,6 +242,7 @@
public abstract void grantEphemeralAccess(int userId, Intent intent,
int targetAppId, int ephemeralAppId);
+ public abstract boolean isInstantAppInstallerComponent(ComponentName component);
/**
* Prunes instant apps and state associated with uninstalled
* instant apps according to the current platform policy.
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index 63d3e7a..44dbcfb 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -21,6 +21,7 @@
import android.os.LooperProto;
import android.util.Log;
import android.util.Printer;
+import android.util.Slog;
import android.util.proto.ProtoOutputStream;
/**
@@ -76,6 +77,9 @@
private Printer mLogging;
private long mTraceTag;
+ /* If set, the looper will show a warning log if a message dispatch takes longer than time. */
+ private long mSlowDispatchThresholdMs;
+
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
@@ -148,17 +152,30 @@
msg.callback + ": " + msg.what);
}
+ final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
+
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
+ final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
+ final long end;
try {
msg.target.dispatchMessage(msg);
+ end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
+ if (slowDispatchThresholdMs > 0) {
+ final long time = end - start;
+ if (time > slowDispatchThresholdMs) {
+ Slog.w(TAG, "Dispatch took " + time + "ms on "
+ + Thread.currentThread().getName() + ", h=" +
+ msg.target + " cb=" + msg.callback + " msg=" + msg.what);
+ }
+ }
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
@@ -226,6 +243,11 @@
mTraceTag = traceTag;
}
+ /** {@hide} */
+ public void setSlowDispatchThresholdMs(long slowDispatchThresholdMs) {
+ mSlowDispatchThresholdMs = slowDispatchThresholdMs;
+ }
+
/**
* Quits the looper.
* <p>
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index b3366d8..8208438 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -487,11 +487,11 @@
* Instructs the zygote to pre-load the classes and native libraries at the given paths
* for the specified abi. Not all zygotes support this function.
*/
- public void preloadPackageForAbi(String packagePath, String libsPath, String abi)
- throws ZygoteStartFailedEx, IOException {
+ public void preloadPackageForAbi(String packagePath, String libsPath, String cacheKey,
+ String abi) throws ZygoteStartFailedEx, IOException {
synchronized(mLock) {
ZygoteState state = openZygoteSocketIfNeeded(abi);
- state.writer.write("3");
+ state.writer.write("4");
state.writer.newLine();
state.writer.write("--preload-package");
@@ -503,6 +503,9 @@
state.writer.write(libsPath);
state.writer.newLine();
+ state.writer.write(cacheKey);
+ state.writer.newLine();
+
state.writer.flush();
}
}
diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java
index 2116847..8e01030 100644
--- a/core/java/android/service/quicksettings/TileService.java
+++ b/core/java/android/service/quicksettings/TileService.java
@@ -433,6 +433,7 @@
public static final void requestListeningState(Context context, ComponentName component) {
Intent intent = new Intent(ACTION_REQUEST_LISTENING);
intent.putExtra(EXTRA_COMPONENT, component);
+ intent.setPackage("com.android.systemui");
context.sendBroadcast(intent, Manifest.permission.BIND_QUICK_SETTINGS_TILE);
}
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 6c73b9b..3f52a9d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -16457,29 +16457,34 @@
}
/**
- * @see #onMovedToDisplay(int)
+ * @see #onMovedToDisplay(int, Configuration)
*/
- void dispatchMovedToDisplay(Display display) {
+ void dispatchMovedToDisplay(Display display, Configuration config) {
mAttachInfo.mDisplay = display;
mAttachInfo.mDisplayState = display.getState();
- onMovedToDisplay(display.getDisplayId());
+ onMovedToDisplay(display.getDisplayId(), config);
}
/**
* Called by the system when the hosting activity is moved from one display to another without
* recreation. This means that the activity is declared to handle all changes to configuration
* that happened when it was switched to another display, so it wasn't destroyed and created
- * again. This call will be followed by {@link #onConfigurationChanged(Configuration)} if the
- * applied configuration actually changed.
+ * again.
+ *
+ * <p>This call will be followed by {@link #onConfigurationChanged(Configuration)} if the
+ * applied configuration actually changed. It is up to app developer to choose whether to handle
+ * the change in this method or in the following {@link #onConfigurationChanged(Configuration)}
+ * call.
*
* <p>Use this callback to track changes to the displays if some functionality relies on an
* association with some display properties.
*
* @param displayId The id of the display to which the view was moved.
+ * @param config Configuration of the resources on new display after move.
*
* @see #onConfigurationChanged(Configuration)
*/
- public void onMovedToDisplay(int displayId) {
+ public void onMovedToDisplay(int displayId, Configuration config) {
}
/**
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index de0ec40..7921938 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3281,13 +3281,13 @@
}
@Override
- void dispatchMovedToDisplay(Display display) {
- super.dispatchMovedToDisplay(display);
+ void dispatchMovedToDisplay(Display display, Configuration config) {
+ super.dispatchMovedToDisplay(display, config);
final int count = mChildrenCount;
final View[] children = mChildren;
for (int i = 0; i < count; i++) {
- children[i].dispatchMovedToDisplay(display);
+ children[i].dispatchMovedToDisplay(display, config);
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1681787..cf52c60 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1106,10 +1106,11 @@
/**
* Notify about move to a different display.
* @param displayId The id of the display where this view root is moved to.
+ * @param config Configuration of the resources on new display after move.
*
* @hide
*/
- public void onMovedToDisplay(int displayId) {
+ public void onMovedToDisplay(int displayId, Configuration config) {
if (mDisplay.getDisplayId() == displayId) {
return;
}
@@ -1120,7 +1121,7 @@
mView.getResources());
mAttachInfo.mDisplayState = mDisplay.getState();
// Internal state updated, now notify the view hierarchy.
- mView.dispatchMovedToDisplay(mDisplay);
+ mView.dispatchMovedToDisplay(mDisplay, config);
}
void pokeDrawLockIfNeeded() {
@@ -3485,15 +3486,16 @@
mActivityConfigCallback.onConfigurationChanged(overrideConfig, newDisplayId);
} else {
// There is no activity callback - update the configuration right away.
- updateConfiguration();
+ updateConfiguration(newDisplayId);
}
mForceNextConfigUpdate = false;
}
/**
* Update display and views if last applied merged configuration changed.
+ * @param newDisplayId Id of new display if moved, {@link Display#INVALID_DISPLAY} otherwise.
*/
- public void updateConfiguration() {
+ public void updateConfiguration(int newDisplayId) {
if (mView == null) {
return;
}
@@ -3503,6 +3505,13 @@
// the one in them which may be newer.
final Resources localResources = mView.getResources();
final Configuration config = localResources.getConfiguration();
+
+ // Handle move to display.
+ if (newDisplayId != INVALID_DISPLAY) {
+ onMovedToDisplay(newDisplayId, config);
+ }
+
+ // Handle configuration change.
if (mForceNextConfigUpdate || mLastConfigurationFromResources.diff(config) != 0) {
// Update the display with new DisplayAdjustments.
mDisplay = ResourcesManager.getInstance().getAdjustedDisplay(
@@ -3674,15 +3683,17 @@
SomeArgs args = (SomeArgs) msg.obj;
final int displayId = args.argi3;
- final boolean displayChanged = mDisplay.getDisplayId() != displayId;
- if (displayChanged) {
- onMovedToDisplay(displayId);
- }
-
final MergedConfiguration mergedConfiguration = (MergedConfiguration) args.arg4;
+ final boolean displayChanged = mDisplay.getDisplayId() != displayId;
+
if (mergedConfiguration != null) {
+ // If configuration changed - notify about that and, maybe, about move to
+ // display.
performConfigurationChange(mergedConfiguration, false /* force */,
displayChanged ? displayId : INVALID_DISPLAY /* same display */);
+ } else if (displayChanged) {
+ // Moved to display without config change - report last applied one.
+ onMovedToDisplay(displayId, mLastConfigurationFromResources);
}
final boolean framesChanged = !mWinFrame.equals(args.arg1)
diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java
index 44309a7..28c2d01 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtype.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtype.java
@@ -520,27 +520,27 @@
}
private HashMap<String, String> getExtraValueHashMap() {
- if (mExtraValueHashMapCache == null) {
- synchronized(this) {
- if (mExtraValueHashMapCache == null) {
- mExtraValueHashMapCache = new HashMap<String, String>();
- final String[] pairs = mSubtypeExtraValue.split(EXTRA_VALUE_PAIR_SEPARATOR);
- final int N = pairs.length;
- for (int i = 0; i < N; ++i) {
- final String[] pair = pairs[i].split(EXTRA_VALUE_KEY_VALUE_SEPARATOR);
- if (pair.length == 1) {
- mExtraValueHashMapCache.put(pair[0], null);
- } else if (pair.length > 1) {
- if (pair.length > 2) {
- Slog.w(TAG, "ExtraValue has two or more '='s");
- }
- mExtraValueHashMapCache.put(pair[0], pair[1]);
- }
+ synchronized (this) {
+ HashMap<String, String> extraValueMap = mExtraValueHashMapCache;
+ if (extraValueMap != null) {
+ return extraValueMap;
+ }
+ extraValueMap = new HashMap<>();
+ final String[] pairs = mSubtypeExtraValue.split(EXTRA_VALUE_PAIR_SEPARATOR);
+ for (int i = 0; i < pairs.length; ++i) {
+ final String[] pair = pairs[i].split(EXTRA_VALUE_KEY_VALUE_SEPARATOR);
+ if (pair.length == 1) {
+ extraValueMap.put(pair[0], null);
+ } else if (pair.length > 1) {
+ if (pair.length > 2) {
+ Slog.w(TAG, "ExtraValue has two or more '='s");
}
+ extraValueMap.put(pair[0], pair[1]);
}
}
+ mExtraValueHashMapCache = extraValueMap;
+ return extraValueMap;
}
- return mExtraValueHashMapCache;
}
/**
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 81c2f5d..71db6b1 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -280,6 +280,44 @@
}
}
+ /**
+ * If the ApplicationInfo provided is for a stub WebView, fix up the object to include the
+ * required values from the donor package. If the ApplicationInfo is for a full WebView,
+ * leave it alone. Throws MissingWebViewPackageException if the donor is missing.
+ */
+ private static void fixupStubApplicationInfo(ApplicationInfo ai, PackageManager pm) {
+ String donorPackageName = null;
+ if (ai.metaData != null) {
+ donorPackageName = ai.metaData.getString("com.android.webview.WebViewDonorPackage");
+ }
+ if (donorPackageName != null) {
+ PackageInfo donorPackage;
+ try {
+ donorPackage = pm.getPackageInfo(
+ donorPackageName,
+ PackageManager.GET_SHARED_LIBRARY_FILES
+ | PackageManager.MATCH_DEBUG_TRIAGED_MISSING
+ | PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.MATCH_FACTORY_ONLY);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new MissingWebViewPackageException("Failed to find donor package: " +
+ donorPackageName);
+ }
+ ApplicationInfo donorInfo = donorPackage.applicationInfo;
+
+ // Replace the stub's code locations with the donor's.
+ ai.sourceDir = donorInfo.sourceDir;
+ ai.splitSourceDirs = donorInfo.splitSourceDirs;
+ ai.nativeLibraryDir = donorInfo.nativeLibraryDir;
+ ai.secondaryNativeLibraryDir = donorInfo.secondaryNativeLibraryDir;
+
+ // Copy the donor's primary and secondary ABIs, since the stub doesn't have native code
+ // and so they are unset.
+ ai.primaryCpuAbi = donorInfo.primaryCpuAbi;
+ ai.secondaryCpuAbi = donorInfo.secondaryCpuAbi;
+ }
+ }
+
private static Context getWebViewContextAndSetProvider() {
Application initialApplication = AppGlobals.getInitialApplication();
try {
@@ -307,9 +345,10 @@
}
// Fetch package info and verify it against the chosen package
PackageInfo newPackageInfo = null;
+ PackageManager pm = initialApplication.getPackageManager();
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "PackageManager.getPackageInfo()");
try {
- newPackageInfo = initialApplication.getPackageManager().getPackageInfo(
+ newPackageInfo = pm.getPackageInfo(
response.packageInfo.packageName,
PackageManager.GET_SHARED_LIBRARY_FILES
| PackageManager.MATCH_DEBUG_TRIAGED_MISSING
@@ -328,12 +367,15 @@
// failure
verifyPackageInfo(response.packageInfo, newPackageInfo);
+ ApplicationInfo ai = newPackageInfo.applicationInfo;
+ fixupStubApplicationInfo(ai, pm);
+
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW,
"initialApplication.createApplicationContext");
try {
// Construct an app context to load the Java code into the current app.
Context webViewContext = initialApplication.createApplicationContext(
- newPackageInfo.applicationInfo,
+ ai,
Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
sPackageInfo = newPackageInfo;
return webViewContext;
@@ -449,7 +491,11 @@
*/
public static int onWebViewProviderChanged(PackageInfo packageInfo) {
String[] nativeLibs = null;
+ String originalSourceDir = packageInfo.applicationInfo.sourceDir;
try {
+ fixupStubApplicationInfo(packageInfo.applicationInfo,
+ AppGlobals.getInitialApplication().getPackageManager());
+
nativeLibs = WebViewFactory.getWebViewNativeLibraryPaths(packageInfo);
if (nativeLibs != null) {
long newVmSize = 0L;
@@ -498,7 +544,7 @@
Log.e(LOGTAG, "error preparing webview native library", t);
}
- WebViewZygote.onWebViewProviderChanged(packageInfo);
+ WebViewZygote.onWebViewProviderChanged(packageInfo, originalSourceDir);
return prepareWebViewInSystemServer(nativeLibs);
}
diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java
index f78d622..2123deb 100644
--- a/core/java/android/webkit/WebViewZygote.java
+++ b/core/java/android/webkit/WebViewZygote.java
@@ -67,6 +67,13 @@
private static PackageInfo sPackage;
/**
+ * Cache key for the selected WebView package's classloader. This is set from
+ * #onWebViewProviderChanged().
+ */
+ @GuardedBy("sLock")
+ private static String sPackageCacheKey;
+
+ /**
* Flag for whether multi-process WebView is enabled. If this is false, the zygote
* will not be started.
*/
@@ -118,9 +125,10 @@
}
}
- public static void onWebViewProviderChanged(PackageInfo packageInfo) {
+ public static void onWebViewProviderChanged(PackageInfo packageInfo, String cacheKey) {
synchronized (sLock) {
sPackage = packageInfo;
+ sPackageCacheKey = cacheKey;
// If multi-process is not enabled, then do not start the zygote service.
if (!sMultiprocessEnabled) {
@@ -210,7 +218,8 @@
TextUtils.join(File.pathSeparator, zipPaths);
Log.d(LOGTAG, "Preloading package " + zip + " " + librarySearchPath);
- sZygote.preloadPackageForAbi(zip, librarySearchPath, Build.SUPPORTED_ABIS[0]);
+ sZygote.preloadPackageForAbi(zip, librarySearchPath, sPackageCacheKey,
+ Build.SUPPORTED_ABIS[0]);
} catch (Exception e) {
Log.e(LOGTAG, "Error connecting to " + serviceName, e);
sZygote = null;
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 78d18fd..ab4cce4 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -523,9 +523,17 @@
/**
* Sets the height of the popup window in pixels. Can also be {@link #MATCH_PARENT}.
*
- * @param height Height of the popup window.
+ * @param height Height of the popup window must be a positive value,
+ * {@link #MATCH_PARENT}, or {@link #WRAP_CONTENT}.
+ *
+ * @throws IllegalArgumentException if height is set to negative value
*/
public void setHeight(int height) {
+ if (height < 0 && ViewGroup.LayoutParams.WRAP_CONTENT != height
+ && ViewGroup.LayoutParams.MATCH_PARENT != height) {
+ throw new IllegalArgumentException(
+ "Invalid height. Must be a positive value, MATCH_PARENT, or WRAP_CONTENT.");
+ }
mDropDownHeight = height;
}
diff --git a/core/java/com/android/internal/os/WebViewZygoteInit.java b/core/java/com/android/internal/os/WebViewZygoteInit.java
index f27c0d4..cc3f58c 100644
--- a/core/java/com/android/internal/os/WebViewZygoteInit.java
+++ b/core/java/com/android/internal/os/WebViewZygoteInit.java
@@ -26,6 +26,7 @@
import android.webkit.WebViewFactory;
import android.webkit.WebViewFactoryProvider;
+import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
@@ -67,16 +68,20 @@
}
@Override
- protected boolean handlePreloadPackage(String packagePath, String libsPath) {
+ protected boolean handlePreloadPackage(String packagePath, String libsPath,
+ String cacheKey) {
// Ask ApplicationLoaders to create and cache a classloader for the WebView APK so that
// our children will reuse the same classloader instead of creating their own.
// This enables us to preload Java and native code in the webview zygote process and
// have the preloaded versions actually be used post-fork.
ClassLoader loader = ApplicationLoaders.getDefault().createAndCacheWebViewClassLoader(
- packagePath, libsPath);
+ packagePath, libsPath, cacheKey);
// Add the APK to the Zygote's list of allowed files for children.
- Zygote.nativeAllowFileAcrossFork(packagePath);
+ String[] packageList = TextUtils.split(packagePath, File.pathSeparator);
+ for (String packageEntry : packageList) {
+ Zygote.nativeAllowFileAcrossFork(packageEntry);
+ }
// Once we have the classloader, look up the WebViewFactoryProvider implementation and
// call preloadInZygote() on it to give it the opportunity to preload the native library
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index e2485e9..a9bec41 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -177,7 +177,7 @@
if (parsedArgs.preloadPackage != null) {
return handlePreloadPackage(parsedArgs.preloadPackage,
- parsedArgs.preloadPackageLibs);
+ parsedArgs.preloadPackageLibs, parsedArgs.preloadPackageCacheKey);
}
if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) {
@@ -314,7 +314,7 @@
return ZygoteInit.isPreloadComplete();
}
- protected boolean handlePreloadPackage(String packagePath, String libsPath) {
+ protected boolean handlePreloadPackage(String packagePath, String libsPath, String cacheKey) {
throw new RuntimeException("Zyogte does not support package preloading");
}
@@ -428,6 +428,7 @@
*/
String preloadPackage;
String preloadPackageLibs;
+ String preloadPackageCacheKey;
/**
* Whether this is a request to start preloading the default resources and classes.
@@ -599,6 +600,7 @@
} else if (arg.equals("--preload-package")) {
preloadPackage = args[++curArg];
preloadPackageLibs = args[++curArg];
+ preloadPackageCacheKey = args[++curArg];
} else if (arg.equals("--preload-default")) {
preloadDefault = true;
} else {
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 7704519..db234e7 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2801,4 +2801,9 @@
<!-- Colon separated list of package names that should be granted Notification Listener access -->
<string name="config_defaultListenerAccessPackages" translatable="false"></string>
+
+ <!-- Maximum size, specified in pixels, to restrain the display space width to. Height and
+ density will be scaled accordingly to maintain aspect ratio. A value of 0 indicates no
+ constraint will be enforced. -->
+ <integer name="config_maxUiWidth">0</integer>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 868e256..4afa8dc 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -189,22 +189,23 @@
<!-- Displayed to tell the user that they cannot change the caller ID setting. -->
<string name="CLIRPermanent">You can\'t change the caller ID setting.</string>
- <!-- Displayed to tell the user that data service is blocked by access control. -->
- <string name="RestrictedOnData">Data service is blocked.</string>
- <!-- Displayed to tell the user that emergency service is blocked by access control. -->
- <string name="RestrictedOnEmergency">Emergency service is blocked.</string>
- <!-- Displayed to tell the user that normal service is blocked by access control. -->
- <string name="RestrictedOnNormal">Voice service is blocked.</string>
- <!-- Displayed to tell the user that all emergency and normal voice services are blocked by access control. -->
- <string name="RestrictedOnAllVoice">All voice services are blocked.</string>
- <!-- Displayed to tell the user that sms service is blocked by access control. -->
- <string name="RestrictedOnSms">SMS service is blocked.</string>
- <!-- Displayed to tell the user that voice/data service is blocked by access control. -->
- <string name="RestrictedOnVoiceData">Voice/data services are blocked.</string>
- <!-- Displayed to tell the user that voice and sms service are blocked by access control. -->
- <string name="RestrictedOnVoiceSms">Voice/SMS services are blocked.</string>
- <!-- Displayed to tell the user that all service is blocked by access control. -->
- <string name="RestrictedOnAll">All voice/data/SMS services are blocked.</string>
+ <!-- Notification title to tell the user that data service is blocked by access control. -->
+ <string name="RestrictedOnDataTitle">No data service</string>
+ <!-- Notification title to tell the user that emergency service is blocked by access control. -->
+ <string name="RestrictedOnEmergencyTitle">No emergency service</string>
+ <!-- Notification title to tell the user that normal service is blocked by access control. -->
+ <string name="RestrictedOnNormalTitle">No voice service</string>
+ <!-- Notification title to tell the user that all emergency and normal voice services are blocked by access control. -->
+ <string name="RestrictedOnAllVoiceTitle">No voice/emergency service</string>
+
+ <!-- Notification content to tell the user that data service is blocked by access control. -->
+ <string name="RestrictedOnDataContent">Your carrier has temporarily suspended data service at this location</string>
+ <!-- Notification content to tell the user that emergency service is blocked by access control. -->
+ <string name="RestrictedOnEmergencyContent">Your carrier has temporarily suspended emergency calls at this location</string>
+ <!-- Notification content to tell the user that normal service is blocked by access control. -->
+ <string name="RestrictedOnNormalContent">Your carrier has temporarily suspended voice calls at this location</string>
+ <!-- Notification content to tell the user that all emergency and normal voice services are blocked by access control. -->
+ <string name="RestrictedOnAllVoiceContent">Your carrier has temporarily suspended voice and emergency calls at this location</string>
<!-- Displayed to tell the user that they should switch their network preference. -->
<string name="NetworkPreferenceSwitchTitle">Can\u2019t reach network</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b23c96c..92436f4 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -507,12 +507,16 @@
<java-symbol type="string" name="Noon" />
<java-symbol type="string" name="PinMmi" />
<java-symbol type="string" name="PwdMmi" />
- <java-symbol type="string" name="RestrictedOnAllVoice" />
- <java-symbol type="string" name="RestrictedOnData" />
- <java-symbol type="string" name="RestrictedOnEmergency" />
- <java-symbol type="string" name="RestrictedOnNormal" />
<java-symbol type="string" name="NetworkPreferenceSwitchSummary" />
<java-symbol type="string" name="NetworkPreferenceSwitchTitle" />
+ <java-symbol type="string" name="RestrictedOnAllVoiceTitle" />
+ <java-symbol type="string" name="RestrictedOnDataTitle" />
+ <java-symbol type="string" name="RestrictedOnEmergencyTitle" />
+ <java-symbol type="string" name="RestrictedOnNormalTitle" />
+ <java-symbol type="string" name="RestrictedOnAllVoiceContent" />
+ <java-symbol type="string" name="RestrictedOnDataContent" />
+ <java-symbol type="string" name="RestrictedOnEmergencyContent" />
+ <java-symbol type="string" name="RestrictedOnNormalContent" />
<java-symbol type="string" name="SetupCallDefault" />
<java-symbol type="string" name="accept" />
<java-symbol type="string" name="activity_chooser_view_see_all" />
@@ -2919,6 +2923,9 @@
<!-- Colon separated list of package names that should be granted Notification Listener access -->
<java-symbol type="string" name="config_defaultListenerAccessPackages" />
+ <!-- maximum width of the display -->
+ <java-symbol type="integer" name="config_maxUiWidth" />
+
<!-- system notification channels -->
<java-symbol type="string" name="notification_channel_virtual_keyboard" />
<java-symbol type="string" name="notification_channel_physical_keyboard" />
diff --git a/graphics/java/android/graphics/Color.java b/graphics/java/android/graphics/Color.java
index 33d19d4..d69f67d 100644
--- a/graphics/java/android/graphics/Color.java
+++ b/graphics/java/android/graphics/Color.java
@@ -22,6 +22,7 @@
import android.annotation.HalfFloat;
import android.annotation.IntRange;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.Size;
import android.util.Half;
@@ -288,7 +289,7 @@
* and <code>(1.0, 0.0, 0.0, 0.5)</code>.</p>
*/
@AnyThread
-public class Color {
+public final class Color {
@ColorInt public static final int BLACK = 0xFF000000;
@ColorInt public static final int DKGRAY = 0xFF444444;
@ColorInt public static final int GRAY = 0xFF888888;
@@ -415,7 +416,7 @@
* to this color space's color model, plus one extra component for
* alpha.
*
- * @return An integer between 4 and 5
+ * @return The integer 4 or 5
*/
@IntRange(from = 4, to = 5)
public int getComponentCount() {
@@ -560,7 +561,37 @@
@NonNull
@Size(min = 4, max = 5)
public float[] getComponents() {
- return Arrays.copyOf(mComponents, mColorSpace.getComponentCount() + 1);
+ return Arrays.copyOf(mComponents, mComponents.length);
+ }
+
+ /**
+ * Copies this color's components in the supplied array. The last element of the
+ * array is always the alpha component.
+ *
+ * @param components An array of floats whose size must be at least
+ * {@link #getComponentCount()}, can be null
+ * @return The array passed as a parameter if not null, or a new array of length
+ * {@link #getComponentCount()}
+ *
+ * @see #getComponent(int)
+ *
+ * @throws IllegalArgumentException If the specified array's length is less than
+ * {@link #getComponentCount()}
+ */
+ @NonNull
+ @Size(min = 4)
+ public float[] getComponents(@Nullable @Size(min = 4) float[] components) {
+ if (components == null) {
+ return Arrays.copyOf(mComponents, mComponents.length);
+ }
+
+ if (components.length < mComponents.length) {
+ throw new IllegalArgumentException("The specified array's length must be at "
+ + "least " + mComponents.length);
+ }
+
+ System.arraycopy(mComponents, 0, components, 0, mComponents.length);
+ return components;
}
/**
@@ -570,7 +601,7 @@
*
* <p>If the requested component index is {@link #getComponentCount()},
* this method returns the alpha component, always in the range
- * \([0..1\).</p>
+ * \([0..1]\).</p>
*
* @see #getComponents()
*
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 64cac3c..f15475c 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -106,7 +106,7 @@
<!-- The default tiles to display in QuickSettings -->
<string name="quick_settings_tiles_default" translatable="false">
- wifi,cell,bt,dnd,flashlight,rotation,battery,airplane
+ wifi,bt,dnd,flashlight,rotation,battery,cell,airplane,cast
</string>
<!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index 716816d..d51fe8a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -51,6 +51,7 @@
import com.android.systemui.statusbar.phone.ExpandableIndicator;
import com.android.systemui.statusbar.phone.MultiUserSwitch;
import com.android.systemui.statusbar.phone.SettingsButton;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener;
import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
@@ -337,6 +338,11 @@
@Override
public void onClick(View v) {
if (v == mSettingsButton) {
+ if (!Dependency.get(DeviceProvisionedController.class).isCurrentUserSetup()) {
+ // If user isn't setup just unlock the device and dump them back at SUW.
+ mActivityStarter.postQSRunnableDismissingKeyguard(() -> { });
+ return;
+ }
MetricsLogger.action(mContext,
mExpanded ? MetricsProto.MetricsEvent.ACTION_QS_EXPANDED_SETTINGS_LAUNCH
: MetricsProto.MetricsEvent.ACTION_QS_COLLAPSED_SETTINGS_LAUNCH);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 1f49c1a..406f107 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -21,6 +21,7 @@
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Bundle;
+import android.support.annotation.VisibleForTesting;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -39,6 +40,8 @@
public class QSFragment extends Fragment implements QS {
private static final String TAG = "QS";
private static final boolean DEBUG = false;
+ private static final String EXTRA_EXPANDED = "expanded";
+ private static final String EXTRA_LISTENING = "listening";
private final Rect mQsBounds = new Rect();
private boolean mQsExpanded;
@@ -85,6 +88,35 @@
mQSCustomizer = view.findViewById(R.id.qs_customize);
mQSCustomizer.setQs(this);
+ if (savedInstanceState != null) {
+ setExpanded(savedInstanceState.getBoolean(EXTRA_EXPANDED));
+ setListening(savedInstanceState.getBoolean(EXTRA_LISTENING));
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (mListening) {
+ setListening(false);
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putBoolean(EXTRA_EXPANDED, mQsExpanded);
+ outState.putBoolean(EXTRA_LISTENING, mListening);
+ }
+
+ @VisibleForTesting
+ boolean isListening() {
+ return mListening;
+ }
+
+ @VisibleForTesting
+ boolean isExpanded() {
+ return mQsExpanded;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
index a751ef4..6e2add4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
@@ -84,12 +84,14 @@
protected void updateIcon(ImageView iv, State state) {
if (!Objects.equals(state.icon, iv.getTag(R.id.qs_icon_tag))) {
+ boolean shouldAnimate = iv.isShown() && mAnimationEnabled
+ && iv.getDrawable() != null;
Drawable d = state.icon != null
- ? iv.isShown() && mAnimationEnabled ? state.icon.getDrawable(mContext)
+ ? shouldAnimate ? state.icon.getDrawable(mContext)
: state.icon.getInvisibleDrawable(mContext) : null;
int padding = state.icon != null ? state.icon.getPadding() : 0;
if (d != null) {
- d.setAutoMirrored(true);
+ d.setAutoMirrored(false);
}
iv.setImageDrawable(d);
iv.setTag(R.id.qs_icon_tag, state.icon);
@@ -114,7 +116,7 @@
if (state.state != mState) {
int color = getColor(state.state);
mState = state.state;
- if (iv.isShown()) {
+ if (iv.isShown() && mTint != 0) {
animateGrayScale(mTint, color, iv);
mTint = color;
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedController.java
index 21f9a79..cae76b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedController.java
@@ -24,6 +24,10 @@
boolean isUserSetup(int currentUser);
int getCurrentUser();
+ default boolean isCurrentUserSetup() {
+ return isUserSetup(getCurrentUser());
+ }
+
interface DeviceProvisionedListener {
default void onDeviceProvisionedChanged() { }
default void onUserSwitched() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java
index 3ee01de..21a96e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java
@@ -19,6 +19,7 @@
import android.annotation.Nullable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
+import android.view.Gravity;
/**
* Drawable for {@link KeyButtonView}s which contains an asset for both normal mode and light
@@ -40,6 +41,9 @@
private KeyButtonDrawable(Drawable[] drawables) {
super(drawables);
+ for (int i = 0; i < drawables.length; i++) {
+ setLayerGravity(i, Gravity.CENTER);
+ }
mutate();
mHasDarkDrawable = drawables.length > 1;
setDarkIntensity(0f);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterTest.java
new file mode 100644
index 0000000..778ab8e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.qs;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import com.android.systemui.R;
+import com.android.systemui.R.id;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.utils.leaks.LeakCheckedTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public class QSFooterTest extends LeakCheckedTest {
+
+ private QSFooter mFooter;
+ private ActivityStarter mActivityStarter;
+ private DeviceProvisionedController mDeviceProvisionedController;
+
+ @Before
+ public void setup() throws Exception {
+ injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
+ mActivityStarter = mDependency.injectMockDependency(ActivityStarter.class);
+ mDeviceProvisionedController = mDependency.injectMockDependency(
+ DeviceProvisionedController.class);
+ TestableLooper.get(this).runWithLooper(() -> {
+ mFooter = (QSFooter) LayoutInflater.from(mContext).inflate(R.layout.qs_footer, null);
+ });
+ }
+
+ @Test
+ public void testSettings_UserNotSetup() {
+ View settingsButton = mFooter.findViewById(id.settings_button);
+ when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(false);
+
+ mFooter.onClick(settingsButton);
+ // Verify Settings wasn't launched.
+ verify(mActivityStarter, never()).startActivity(any(), anyBoolean());
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index d77ed3d..673ffc5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -15,8 +15,11 @@
package com.android.systemui.qs;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
+import android.app.FragmentController;
+import android.app.FragmentManagerNonConfig;
import android.os.Looper;
import com.android.internal.logging.MetricsLogger;
@@ -24,6 +27,7 @@
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import android.os.Parcelable;
import android.testing.AndroidTestingRunner;
import com.android.systemui.SysuiBaseFragmentTest;
@@ -90,4 +94,23 @@
host.destroy();
processAllMessages();
}
+
+ @Test
+ public void testSaveState() {
+ QSFragment qs = (QSFragment) mFragment;
+
+ mFragments.dispatchResume();
+ processAllMessages();
+
+ qs.setListening(true);
+ qs.setExpanded(true);
+ processAllMessages();
+ recreateFragment();
+ processAllMessages();
+
+ // Get the reference to the new fragment.
+ qs = (QSFragment) mFragment;
+ assertTrue(qs.isListening());
+ assertTrue(qs.isExpanded());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java
new file mode 100644
index 0000000..59483f2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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.qs.tileimpl;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.res.ColorStateList;
+import android.graphics.drawable.Drawable;
+import android.service.quicksettings.Tile;
+import android.testing.AndroidTestingRunner;
+import android.testing.UiThreadTest;
+import android.widget.ImageView;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.qs.QSTile.Icon;
+import com.android.systemui.plugins.qs.QSTile.State;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatcher;
+
+@RunWith(AndroidTestingRunner.class)
+@UiThreadTest
+public class QSIconViewImplTest extends SysuiTestCase {
+
+ private QSIconViewImpl mIconView;
+
+ @Before
+ public void setup() {
+ mIconView = new QSIconViewImpl(mContext);
+ }
+
+ @Test
+ public void testNoFirstAnimation() {
+ ImageView iv = mock(ImageView.class);
+ State s = new State();
+ when(iv.isShown()).thenReturn(true);
+
+ // No current icon, only the static drawable should be used.
+ s.icon = mock(Icon.class);
+ when(iv.getDrawable()).thenReturn(null);
+ mIconView.updateIcon(iv, s);
+ verify(s.icon, never()).getDrawable(any());
+ verify(s.icon).getInvisibleDrawable(any());
+
+ // Has icon, should use the standard (animated) form.
+ s.icon = mock(Icon.class);
+ when(iv.getDrawable()).thenReturn(mock(Drawable.class));
+ mIconView.updateIcon(iv, s);
+ verify(s.icon).getDrawable(any());
+ verify(s.icon, never()).getInvisibleDrawable(any());
+ }
+
+ @Test
+ public void testNoFirstFade() {
+ ImageView iv = mock(ImageView.class);
+ State s = new State();
+ s.state = Tile.STATE_ACTIVE;
+ int desiredColor = mIconView.getColor(s.state);
+ when(iv.isShown()).thenReturn(true);
+
+ mIconView.setIcon(iv, s);
+ verify(iv).setImageTintList(argThat(stateList -> stateList.getColors()[0] == desiredColor));
+ }
+}
diff --git a/services/core/java/com/android/server/UiThread.java b/services/core/java/com/android/server/UiThread.java
index 1bc6250..fd88d26 100644
--- a/services/core/java/com/android/server/UiThread.java
+++ b/services/core/java/com/android/server/UiThread.java
@@ -17,6 +17,7 @@
package com.android.server;
import android.os.Handler;
+import android.os.Looper;
import android.os.Process;
import android.os.Trace;
@@ -26,20 +27,28 @@
* on it to avoid UI jank.
*/
public final class UiThread extends ServiceThread {
+ private static final long SLOW_DISPATCH_THRESHOLD_MS = 100;
private static UiThread sInstance;
private static Handler sHandler;
private UiThread() {
super("android.ui", Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
+ }
+
+ @Override
+ public void run() {
// Make sure UiThread is in the fg stune boost group
Process.setThreadGroup(Process.myTid(), Process.THREAD_GROUP_TOP_APP);
+ super.run();
}
private static void ensureThreadLocked() {
if (sInstance == null) {
sInstance = new UiThread();
sInstance.start();
- sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ final Looper looper = sInstance.getLooper();
+ looper.setTraceTag(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ looper.setSlowDispatchThresholdMs(SLOW_DISPATCH_THRESHOLD_MS);
sHandler = new Handler(sInstance.getLooper());
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7a83436..ead1b26 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3929,8 +3929,13 @@
if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
// Debuggable apps may include a wrapper script with their library directory.
String wrapperFileName = app.info.nativeLibraryDir + "/wrap.sh";
- if (new File(wrapperFileName).exists()) {
- invokeWith = "/system/bin/logwrapper " + wrapperFileName;
+ StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+ try {
+ if (new File(wrapperFileName).exists()) {
+ invokeWith = "/system/bin/logwrapper " + wrapperFileName;
+ }
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
}
}
@@ -18277,6 +18282,10 @@
return record.info.isInstantApp();
}
// Otherwise check with PackageManager.
+ if (callerPackage == null) {
+ Slog.e(TAG, "isInstantApp with an application's uid, no record, and no package name");
+ throw new IllegalArgumentException("Calling application did not provide package name");
+ }
mAppOpsService.checkPackage(uid, callerPackage);
try {
IPackageManager pm = AppGlobals.getPackageManager();
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 4bd06b7..9258539 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -640,6 +640,18 @@
final Intent ephemeralIntent = new Intent(intent);
// Don't modify the client's object!
intent = new Intent(intent);
+ if (componentSpecified
+ && intent.getData() != null
+ && Intent.ACTION_VIEW.equals(intent.getAction())
+ && intent.hasCategory(Intent.CATEGORY_BROWSABLE)
+ && mService.getPackageManagerInternalLocked()
+ .isInstantAppInstallerComponent(intent.getComponent())) {
+ // intercept intents targeted directly to the ephemeral installer the
+ // ephemeral installer should never be started with a raw URL; instead
+ // adjust the intent so it looks like a "normal" instant app launch
+ intent.setComponent(null /*component*/);
+ componentSpecified = false;
+ }
ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);
if (rInfo == null) {
@@ -1453,6 +1465,12 @@
return intentActivity;
}
+ /**
+ * Figure out which task and activity to bring to front when we have found an existing matching
+ * activity record in history. May also clear the task if needed.
+ * @param intentActivity Existing matching activity.
+ * @return {@link ActivityRecord} brought to front.
+ */
private ActivityRecord setTargetStackAndMoveToFrontIfNeeded(ActivityRecord intentActivity) {
mTargetStack = intentActivity.getStack();
mTargetStack.mLastPausedActivity = null;
@@ -1514,6 +1532,14 @@
"bringToFrontInsteadOfAdjacentLaunch");
}
mMovedToFront = true;
+ } else if (launchStack.mDisplayId != mTargetStack.mDisplayId) {
+ // Target and computed stacks are on different displays and we've
+ // found a matching task - move the existing instance to that display and
+ // move it to front.
+ intentActivity.task.reparent(launchStack.mStackId, ON_TOP,
+ REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME,
+ "reparentToDisplay");
+ mMovedToFront = true;
}
mOptions = null;
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index bbad493..1a27a39 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -907,7 +907,12 @@
Bundle finalExtras = new Bundle(extras);
String packageName = syncAdapterInfo.componentName.getPackageName();
// If the app did not run and has no account access, done
- if (!mPackageManagerInternal.wasPackageEverLaunched(packageName, userId)) {
+ try {
+ if (!mPackageManagerInternal.wasPackageEverLaunched(packageName, userId)) {
+ continue;
+ }
+ } catch (IllegalArgumentException e) {
+ // Package not found, race with an uninstall
continue;
}
mAccountManagerInternal.requestAccountAccess(account.account,
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 7f75c83..53a8092 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -772,7 +772,12 @@
private final class SessionStub extends ISession.Stub {
@Override
public void destroy() {
- mService.destroySession(MediaSessionRecord.this);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mService.destroySession(MediaSessionRecord.this);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index fc45344..93e30ff 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -180,6 +180,7 @@
import com.android.server.DeviceIdleController;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
+import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
import com.android.server.power.BatterySaverPolicy.ServiceType;
@@ -310,6 +311,9 @@
private static final int MSG_SET_FIREWALL_RULES = 14;
private static final int MSG_RESET_FIREWALL_RULES_BY_UID = 15;
+ private static final int UID_MSG_STATE_CHANGED = 100;
+ private static final int UID_MSG_GONE = 101;
+
private final Context mContext;
private final IActivityManager mActivityManager;
private final INetworkStatsService mNetworkStats;
@@ -420,6 +424,9 @@
mListeners = new RemoteCallbackList<>();
final Handler mHandler;
+ final Handler mUidEventHandler;
+
+ private final ServiceThread mUidEventThread;
@GuardedBy("allLocks")
private final AtomicFile mPolicyFile;
@@ -471,6 +478,12 @@
thread.start();
mHandler = new Handler(thread.getLooper(), mHandlerCallback);
+ // We create another thread for the UID events, which are more time-critical.
+ mUidEventThread = new ServiceThread(TAG + ".uid", Process.THREAD_PRIORITY_FOREGROUND,
+ /*allowIo=*/ false);
+ mUidEventThread.start();
+ mUidEventHandler = new Handler(mUidEventThread.getLooper(), mUidEventHandlerCallback);
+
mSuppressDefaultPolicy = suppressDefaultPolicy;
mPolicyFile = new AtomicFile(new File(systemDir, "netpolicy.xml"));
@@ -774,26 +787,12 @@
final private IUidObserver mUidObserver = new IUidObserver.Stub() {
@Override public void onUidStateChanged(int uid, int procState,
long procStateSeq) throws RemoteException {
- Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "onUidStateChanged");
- try {
- synchronized (mUidRulesFirstLock) {
- // We received a uid state change callback, add it to the history so that it
- // will be useful for debugging.
- mObservedHistory.addProcStateSeqUL(uid, procStateSeq);
- // Now update the network policy rules as per the updated uid state.
- updateUidStateUL(uid, procState);
- // Updating the network rules is done, so notify AMS about this.
- mActivityManagerInternal.notifyNetworkPolicyRulesUpdated(uid, procStateSeq);
- }
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
- }
+ mUidEventHandler.obtainMessage(UID_MSG_STATE_CHANGED,
+ uid, procState, procStateSeq).sendToTarget();
}
@Override public void onUidGone(int uid, boolean disabled) throws RemoteException {
- synchronized (mUidRulesFirstLock) {
- removeUidStateUL(uid);
- }
+ mUidEventHandler.obtainMessage(UID_MSG_GONE, uid, 0).sendToTarget();
}
@Override public void onUidActive(int uid) throws RemoteException {
@@ -3317,7 +3316,7 @@
}
}
- private Handler.Callback mHandlerCallback = new Handler.Callback() {
+ private final Handler.Callback mHandlerCallback = new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
@@ -3441,9 +3440,61 @@
}
}
}
+ };
+
+ private final Handler.Callback mUidEventHandlerCallback = new Handler.Callback() {
+ @Override
+ public boolean handleMessage(Message msg) {
+ switch (msg.what) {
+ case UID_MSG_STATE_CHANGED: {
+ final int uid = msg.arg1;
+ final int procState = msg.arg2;
+ final long procStateSeq = (Long) msg.obj;
+
+ handleUidChanged(uid, procState, procStateSeq);
+ return true;
+ }
+ case UID_MSG_GONE: {
+ final int uid = msg.arg1;
+ handleUidGone(uid);
+ return true;
+ }
+ default: {
+ return false;
+ }
+ }
+ }
};
+ void handleUidChanged(int uid, int procState, long procStateSeq) {
+ Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "onUidStateChanged");
+ try {
+ synchronized (mUidRulesFirstLock) {
+ // We received a uid state change callback, add it to the history so that it
+ // will be useful for debugging.
+ mObservedHistory.addProcStateSeqUL(uid, procStateSeq);
+ // Now update the network policy rules as per the updated uid state.
+ updateUidStateUL(uid, procState);
+ // Updating the network rules is done, so notify AMS about this.
+ mActivityManagerInternal.notifyNetworkPolicyRulesUpdated(uid, procStateSeq);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
+ }
+ }
+
+ void handleUidGone(int uid) {
+ Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "onUidGone");
+ try {
+ synchronized (mUidRulesFirstLock) {
+ removeUidStateUL(uid);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
+ }
+ }
+
private void broadcastRestrictBackgroundChanged(int uid, Boolean changed) {
final PackageManager pm = mContext.getPackageManager();
final String[] packages = pm.getPackagesForUid(uid);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 8cc9375..621e37b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -842,6 +842,8 @@
/** Component used to install ephemeral applications */
ComponentName mInstantAppInstallerComponent;
+ /** Component used to show resolver settings for Instant Apps */
+ ComponentName mInstantAppResolverSettingsComponent;
ActivityInfo mInstantAppInstallerActivity;
final ResolveInfo mInstantAppInstallerInfo = new ResolveInfo();
@@ -2890,6 +2892,7 @@
mInstantAppResolverConnection = null;
}
updateInstantAppInstallerLocked();
+ mInstantAppResolverSettingsComponent = getEphemeralResolverSettingsLPr();
// Read and update the usage of dex files.
// Do this at the end of PM init so that all the packages have their
@@ -3196,6 +3199,37 @@
}
}
+ private @Nullable ComponentName getEphemeralResolverSettingsLPr() {
+ final Intent intent = new Intent(Intent.ACTION_EPHEMERAL_RESOLVER_SETTINGS);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ final int resolveFlags =
+ MATCH_DIRECT_BOOT_AWARE
+ | MATCH_DIRECT_BOOT_UNAWARE
+ | (!Build.IS_DEBUGGABLE ? MATCH_SYSTEM_ONLY : 0);
+ final List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, null,
+ resolveFlags, UserHandle.USER_SYSTEM);
+ Iterator<ResolveInfo> iter = matches.iterator();
+ while (iter.hasNext()) {
+ final ResolveInfo rInfo = iter.next();
+ final PackageSetting ps = mSettings.mPackages.get(rInfo.activityInfo.packageName);
+ if (ps != null) {
+ final PermissionsState permissionsState = ps.getPermissionsState();
+ if (permissionsState.hasPermission(Manifest.permission.ACCESS_INSTANT_APPS, 0)) {
+ continue;
+ }
+ }
+ iter.remove();
+ }
+ if (matches.size() == 0) {
+ return null;
+ } else if (matches.size() == 1) {
+ return matches.get(0).getComponentInfo().getComponentName();
+ } else {
+ throw new RuntimeException(
+ "There must be at most one ephemeral resolver settings; found " + matches);
+ }
+ }
+
private void primeDomainVerificationsLPw(int userId) {
if (DEBUG_DOMAIN_VERIFICATION) {
Slog.d(TAG, "Priming domain verifications in user " + userId);
@@ -5788,6 +5822,10 @@
return false;
}
if (ps.getInstantApp(userId)) {
+ if (DEBUG_EPHEMERAL) {
+ Slog.v(TAG, "DENY instant app installed;"
+ + " pkg: " + packageName);
+ }
return false;
}
}
@@ -6267,7 +6305,6 @@
intent, resolvedType, flags, userId), userId);
addEphemeral = !ephemeralDisabled
&& isEphemeralAllowed(intent, result, userId, false /*skipPackageCheck*/);
-
// Check for cross profile results.
boolean hasNonNegativePriorityResult = hasNonNegativePriority(result);
xpResolveInfo = queryCrossProfileIntents(
@@ -6323,7 +6360,7 @@
} else {
// the caller wants to resolve for a particular package; however, there
// were no installed results, so, try to find an ephemeral result
- addEphemeral = !ephemeralDisabled
+ addEphemeral = !ephemeralDisabled
&& isEphemeralAllowed(
intent, null /*result*/, userId, true /*skipPackageCheck*/);
result = new ArrayList<ResolveInfo>();
@@ -23073,6 +23110,13 @@
}
@Override
+ public boolean isInstantAppInstallerComponent(ComponentName component) {
+ synchronized (mPackages) {
+ return component != null && component.equals(mInstantAppInstallerComponent);
+ }
+ }
+
+ @Override
public void pruneInstantApps() {
synchronized (mPackages) {
mInstantAppRegistry.pruneInstantAppsLPw();
@@ -23313,4 +23357,9 @@
}
return checkUidPermission(appOpPermission, uid) == PERMISSION_GRANTED;
}
+
+ @Override
+ public ComponentName getInstantAppResolverSettingsComponent() {
+ return mInstantAppResolverSettingsComponent;
+ }
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 8f391a7..aa85574 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -175,6 +175,7 @@
private boolean mTmpRecoveringMemory;
private boolean mUpdateImeTarget;
private boolean mTmpInitial;
+ private int mMaxUiWidth;
// Mapping from a token IBinder to a WindowToken object on this display.
private final HashMap<IBinder, WindowToken> mTokenMap = new HashMap();
@@ -1559,6 +1560,39 @@
}
}
+ /** Sets the maximum width the screen resolution can be */
+ void setMaxUiWidth(int width) {
+ if (DEBUG_DISPLAY) {
+ Slog.v(TAG_WM, "Setting max ui width:" + width + " on display:" + getDisplayId());
+ }
+
+ mMaxUiWidth = width;
+
+ // Update existing metrics.
+ updateBaseDisplayMetrics(mBaseDisplayWidth, mBaseDisplayHeight, mBaseDisplayDensity);
+ }
+
+ /** Update base (override) display metrics. */
+ void updateBaseDisplayMetrics(int baseWidth, int baseHeight, int baseDensity) {
+ mBaseDisplayWidth = baseWidth;
+ mBaseDisplayHeight = baseHeight;
+ mBaseDisplayDensity = baseDensity;
+
+ if (mMaxUiWidth > 0 && mBaseDisplayWidth > mMaxUiWidth) {
+ mBaseDisplayHeight = (mMaxUiWidth * mBaseDisplayHeight) / mBaseDisplayWidth;
+ mBaseDisplayDensity = (mMaxUiWidth * mBaseDisplayDensity) / mBaseDisplayWidth;
+ mBaseDisplayWidth = mMaxUiWidth;
+
+ if (DEBUG_DISPLAY) {
+ Slog.v(TAG_WM, "Applying config restraints:" + mBaseDisplayWidth + "x"
+ + mBaseDisplayHeight + " at density:" + mBaseDisplayDensity
+ + " on display:" + getDisplayId());
+ }
+ }
+
+ mBaseDisplayRect.set(0, 0, mBaseDisplayWidth, mBaseDisplayHeight);
+ }
+
void getContentRect(Rect out) {
out.set(mContentRect);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index fa9c2a7..0dc74d7 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -385,6 +385,7 @@
final boolean mAllowBootMessages;
final boolean mLimitedAlphaCompositing;
+ final int mMaxUiWidth;
final WindowManagerPolicy mPolicy;
@@ -949,6 +950,8 @@
com.android.internal.R.integer.config_drawLockTimeoutMillis);
mAllowAnimationsInLowPowerMode = context.getResources().getBoolean(
com.android.internal.R.bool.config_allowAnimationsInLowPowerMode);
+ mMaxUiWidth = context.getResources().getInteger(
+ com.android.internal.R.integer.config_maxUiWidth);
mInputManager = inputManager; // Must be before createDisplayContentLocked.
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
mDisplaySettings = new DisplaySettings();
@@ -4572,6 +4575,9 @@
synchronized(mWindowMap) {
final DisplayContent displayContent = getDefaultDisplayContentLocked();
+ if (mMaxUiWidth > 0) {
+ displayContent.setMaxUiWidth(mMaxUiWidth);
+ }
readForcedDisplayPropertiesLocked(displayContent);
mDisplayReady = true;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java
index 9b4de043..70c7e58 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java
@@ -26,6 +26,7 @@
import android.os.Message;
import android.os.SystemClock;
import android.util.Log;
+import android.util.LongSparseArray;
import com.android.internal.annotations.GuardedBy;
@@ -44,12 +45,21 @@
// If this value changes, update DevicePolicyManager#retrieveNetworkLogs() javadoc
private static final int MAX_EVENTS_PER_BATCH = 1200;
- private static final long BATCH_FINALIZATION_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(90);
- private static final long BATCH_FINALIZATION_TIMEOUT_ALARM_INTERVAL_MS =
- TimeUnit.MINUTES.toMillis(30);
+
+ /**
+ * Maximum number of batches to store in memory. If more batches are generated and the DO
+ * doesn't fetch them, we will discard the oldest one.
+ */
+ private static final int MAX_BATCHES = 5;
+
+ private static final long BATCH_FINALIZATION_TIMEOUT_MS = 90 * 60 * 1000; // 1.5h
+ private static final long BATCH_FINALIZATION_TIMEOUT_ALARM_INTERVAL_MS = 30 * 60 * 1000; // 30m
private static final String NETWORK_LOGGING_TIMEOUT_ALARM_TAG = "NetworkLogging.batchTimeout";
+ /** Delay after which older batches get discarded after a retrieval. */
+ private static final long RETRIEVED_BATCH_DISCARD_DELAY_MS = 5 * 60 * 1000; // 5m
+
private final DevicePolicyManagerService mDpm;
private final AlarmManager mAlarmManager;
@@ -66,22 +76,27 @@
static final int LOG_NETWORK_EVENT_MSG = 1;
- // threadsafe as it's Handler's thread confined
+ /** Network events accumulated so far to be finalized into a batch at some point. */
@GuardedBy("this")
- private ArrayList<NetworkEvent> mNetworkEvents = new ArrayList<NetworkEvent>();
+ private ArrayList<NetworkEvent> mNetworkEvents = new ArrayList<>();
+ /**
+ * Up to {@code MAX_BATCHES} finalized batches of logs ready to be retrieved by the DO. Already
+ * retrieved batches are discarded after {@code RETRIEVED_BATCH_DISCARD_DELAY_MS}.
+ */
@GuardedBy("this")
- private ArrayList<NetworkEvent> mFullBatch;
+ private final LongSparseArray<ArrayList<NetworkEvent>> mBatches =
+ new LongSparseArray<>(MAX_BATCHES);
@GuardedBy("this")
private boolean mPaused = false;
// each full batch is represented by its token, which the DPC has to provide back to retrieve it
@GuardedBy("this")
- private long mCurrentFullBatchToken;
+ private long mCurrentBatchToken;
@GuardedBy("this")
- private long mLastRetrievedFullBatchToken;
+ private long mLastRetrievedBatchToken;
NetworkLoggingHandler(Looper looper, DevicePolicyManagerService dpm) {
super(looper);
@@ -93,7 +108,7 @@
public void handleMessage(Message msg) {
switch (msg.what) {
case LOG_NETWORK_EVENT_MSG: {
- NetworkEvent networkEvent = msg.getData().getParcelable(NETWORK_EVENT_KEY);
+ final NetworkEvent networkEvent = msg.getData().getParcelable(NETWORK_EVENT_KEY);
if (networkEvent != null) {
synchronized (NetworkLoggingHandler.this) {
mNetworkEvents.add(networkEvent);
@@ -113,6 +128,8 @@
void scheduleBatchFinalization() {
final long when = SystemClock.elapsedRealtime() + BATCH_FINALIZATION_TIMEOUT_MS;
+ // We use alarm manager and not just postDelayed here to ensure the batch gets finalized
+ // even if the device goes to sleep.
mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP, when,
BATCH_FINALIZATION_TIMEOUT_ALARM_INTERVAL_MS, NETWORK_LOGGING_TIMEOUT_ALARM_TAG,
mBatchTimeoutAlarmListener, this);
@@ -131,62 +148,80 @@
return;
}
- Log.d(TAG, "Resumed network logging. Current batch="
- + mCurrentFullBatchToken + ", LastRetrievedBatch=" + mLastRetrievedFullBatchToken);
+ Log.d(TAG, "Resumed network logging. Current batch=" + mCurrentBatchToken
+ + ", LastRetrievedBatch=" + mLastRetrievedBatchToken);
mPaused = false;
- // If there is a full batch ready that the device owner hasn't been notified about, do it
- // now.
- if (mFullBatch != null && mFullBatch.size() > 0
- && mLastRetrievedFullBatchToken != mCurrentFullBatchToken) {
+ // If there is a batch ready that the device owner hasn't been notified about, do it now.
+ if (mBatches.size() > 0 && mLastRetrievedBatchToken != mCurrentBatchToken) {
scheduleBatchFinalization();
notifyDeviceOwnerLocked();
}
}
synchronized void discardLogs() {
- mFullBatch = null;
- mNetworkEvents = new ArrayList<NetworkEvent>();
+ mBatches.clear();
+ mNetworkEvents = new ArrayList<>();
Log.d(TAG, "Discarded all network logs");
}
@GuardedBy("this")
private void finalizeBatchAndNotifyDeviceOwnerLocked() {
if (mNetworkEvents.size() > 0) {
- // finalize the batch and start a new one from scratch
- mFullBatch = mNetworkEvents;
- mCurrentFullBatchToken++;
- mNetworkEvents = new ArrayList<NetworkEvent>();
+ // Finalize the batch and start a new one from scratch.
+ if (mBatches.size() >= MAX_BATCHES) {
+ // Remove the oldest batch if we hit the limit.
+ mBatches.removeAt(0);
+ }
+ mCurrentBatchToken++;
+ mBatches.append(mCurrentBatchToken, mNetworkEvents);
+ mNetworkEvents = new ArrayList<>();
if (!mPaused) {
notifyDeviceOwnerLocked();
}
} else {
- // don't notify the DO, since there are no events; DPC can still retrieve
+ // Don't notify the DO, since there are no events; DPC can still retrieve
// the last full batch if not paused.
Log.d(TAG, "Was about to finalize the batch, but there were no events to send to"
- + " the DPC, the batchToken of last available batch: "
- + mCurrentFullBatchToken);
+ + " the DPC, the batchToken of last available batch: " + mCurrentBatchToken);
}
- // regardless of whether the batch was non-empty schedule a new finalization after timeout
+ // Regardless of whether the batch was non-empty schedule a new finalization after timeout.
scheduleBatchFinalization();
}
+ /** Sends a notification to the DO. Should only be called when there is a batch available. */
@GuardedBy("this")
private void notifyDeviceOwnerLocked() {
- Bundle extras = new Bundle();
- extras.putLong(DeviceAdminReceiver.EXTRA_NETWORK_LOGS_TOKEN, mCurrentFullBatchToken);
- extras.putInt(DeviceAdminReceiver.EXTRA_NETWORK_LOGS_COUNT, mFullBatch.size());
+ final Bundle extras = new Bundle();
+ final int lastBatchSize = mBatches.valueAt(mBatches.size() - 1).size();
+ extras.putLong(DeviceAdminReceiver.EXTRA_NETWORK_LOGS_TOKEN, mCurrentBatchToken);
+ extras.putInt(DeviceAdminReceiver.EXTRA_NETWORK_LOGS_COUNT, lastBatchSize);
Log.d(TAG, "Sending network logging batch broadcast to device owner, batchToken: "
- + mCurrentFullBatchToken);
+ + mCurrentBatchToken);
mDpm.sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_NETWORK_LOGS_AVAILABLE, extras);
}
- synchronized List<NetworkEvent> retrieveFullLogBatch(long batchToken) {
- if (batchToken != mCurrentFullBatchToken) {
+ synchronized List<NetworkEvent> retrieveFullLogBatch(final long batchToken) {
+ final int index = mBatches.indexOfKey(batchToken);
+ if (index < 0) {
+ // Invalid token or batch has already been discarded.
return null;
}
- mLastRetrievedFullBatchToken = mCurrentFullBatchToken;
- return mFullBatch;
+
+ // Schedule this and older batches to be discarded after a delay to lessen memory load
+ // without interfering with the admin's ability to collect logs out-of-order.
+ // It isn't critical and we allow it to be delayed further if the phone sleeps, so we don't
+ // use the alarm manager here.
+ postDelayed(() -> {
+ synchronized(this) {
+ while (mBatches.size() > 0 && mBatches.keyAt(0) <= batchToken) {
+ mBatches.removeAt(0);
+ }
+ }
+ }, RETRIEVED_BATCH_DISCARD_DELAY_MS);
+
+ mLastRetrievedBatchToken = batchToken;
+ return mBatches.valueAt(index);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index dd94a21..1729cee 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -254,6 +254,48 @@
assertEquals(window1, sWm.mRoot.computeFocusedWindow());
}
+ /**
+ * This tests setting the maximum ui width on a display.
+ */
+ @Test
+ public void testMaxUiWidth() throws Exception {
+ final int baseWidth = 1440;
+ final int baseHeight = 2560;
+ final int baseDensity = 300;
+
+ sDisplayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity);
+
+ final int maxWidth = 300;
+ final int resultingHeight = (maxWidth * baseHeight) / baseWidth;
+ final int resultingDensity = (maxWidth * baseDensity) / baseWidth;
+
+ sDisplayContent.setMaxUiWidth(maxWidth);
+ verifySizes(sDisplayContent, maxWidth, resultingHeight, resultingDensity);
+
+ // Assert setting values again does not change;
+ sDisplayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity);
+ verifySizes(sDisplayContent, maxWidth, resultingHeight, resultingDensity);
+
+ final int smallerWidth = 200;
+ final int smallerHeight = 400;
+ final int smallerDensity = 100;
+
+ // Specify smaller dimension, verify that it is honored
+ sDisplayContent.updateBaseDisplayMetrics(smallerWidth, smallerHeight, smallerDensity);
+ verifySizes(sDisplayContent, smallerWidth, smallerHeight, smallerDensity);
+
+ // Verify that setting the max width to a greater value than the base width has no effect
+ sDisplayContent.setMaxUiWidth(maxWidth);
+ verifySizes(sDisplayContent, smallerWidth, smallerHeight, smallerDensity);
+ }
+
+ private static void verifySizes(DisplayContent displayContent, int expectedBaseWidth,
+ int expectedBaseHeight, int expectedBaseDensity) {
+ assertEquals(displayContent.mBaseDisplayWidth, expectedBaseWidth);
+ assertEquals(displayContent.mBaseDisplayHeight, expectedBaseHeight);
+ assertEquals(displayContent.mBaseDisplayDensity, expectedBaseDensity);
+ }
+
private void assertForAllWindowsOrder(List<WindowState> expectedWindows) {
final LinkedList<WindowState> actualWindows = new LinkedList();
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index f1cf441..d69f933 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -554,7 +554,7 @@
boolean usbDataUnlocked) {
if (DEBUG) {
Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", "
- + "forceRestart=" + forceRestart);
+ + "forceRestart=" + forceRestart + ", usbDataUnlocked=" + usbDataUnlocked);
}
if (usbDataUnlocked != mUsbDataUnlocked) {
@@ -878,7 +878,12 @@
setEnabledFunctions(functions, false, msg.arg1 == 1);
break;
case MSG_UPDATE_USER_RESTRICTIONS:
- setEnabledFunctions(mCurrentFunctions, false, mUsbDataUnlocked);
+ // Restart the USB stack if USB transfer is enabled but no longer allowed.
+ final boolean forceRestart = mUsbDataUnlocked
+ && isUsbDataTransferActive()
+ && !isUsbTransferAllowed();
+ setEnabledFunctions(
+ mCurrentFunctions, forceRestart, mUsbDataUnlocked && !forceRestart);
break;
case MSG_SYSTEM_READY:
updateUsbNotification();
@@ -902,12 +907,10 @@
case MSG_USER_SWITCHED: {
if (mCurrentUser != msg.arg1) {
// Restart the USB stack and re-apply user restrictions for MTP or PTP.
- final boolean active = UsbManager.containsFunction(mCurrentFunctions,
- UsbManager.USB_FUNCTION_MTP)
- || UsbManager.containsFunction(mCurrentFunctions,
- UsbManager.USB_FUNCTION_PTP);
- if (mUsbDataUnlocked && active && mCurrentUser != UserHandle.USER_NULL) {
- Slog.v(TAG, "Current user switched to " + mCurrentUser
+ if (mUsbDataUnlocked
+ && isUsbDataTransferActive()
+ && mCurrentUser != UserHandle.USER_NULL) {
+ Slog.v(TAG, "Current user switched to " + msg.arg1
+ "; resetting USB host stack for MTP or PTP");
// avoid leaking sensitive data from previous user
setEnabledFunctions(mCurrentFunctions, true, false);
@@ -928,6 +931,11 @@
}
}
+ private boolean isUsbDataTransferActive() {
+ return UsbManager.containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP)
+ || UsbManager.containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP);
+ }
+
public UsbAccessory getCurrentAccessory() {
return mCurrentAccessory;
}
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 506f406..960a2d9 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -1118,4 +1118,12 @@
public int getInstallReason(String packageName, UserHandle user) {
throw new UnsupportedOperationException();
}
+
+ /**
+ * @hide
+ */
+ @Override
+ public ComponentName getInstantAppResolverSettingsComponent() {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/tests/testables/src/android/testing/BaseFragmentTest.java b/tests/testables/src/android/testing/BaseFragmentTest.java
index 53841d5..b09bcde 100644
--- a/tests/testables/src/android/testing/BaseFragmentTest.java
+++ b/tests/testables/src/android/testing/BaseFragmentTest.java
@@ -133,14 +133,7 @@
public void testRecreate() {
mFragments.dispatchResume();
processAllMessages();
- mFragments.dispatchPause();
- Parcelable p = mFragments.saveAllState();
- mFragments.dispatchDestroy();
-
- mFragments = FragmentController.createController(new HostCallbacks());
- mFragments.attachHost(null);
- mFragments.restoreAllState(p, (FragmentManagerNonConfig) null);
- mFragments.dispatchResume();
+ recreateFragment();
processAllMessages();
}
@@ -154,6 +147,18 @@
processAllMessages();
}
+ protected void recreateFragment() {
+ mFragments.dispatchPause();
+ Parcelable p = mFragments.saveAllState();
+ mFragments.dispatchDestroy();
+
+ mFragments = FragmentController.createController(new HostCallbacks());
+ mFragments.attachHost(null);
+ mFragments.restoreAllState(p, (FragmentManagerNonConfig) null);
+ mFragments.dispatchResume();
+ mFragment = mFragments.getFragmentManager().findFragmentById(VIEW_ID);
+ }
+
protected void attachFragmentToWindow() {
ViewUtils.attachView(mView);
TestableLooper.get(this).processMessages(1);
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 3330b1a..2bf5206 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -1403,7 +1403,8 @@
String8 src = it.getFile()->getPrintableSource();
err = compileXmlFile(bundle, assets, String16(it.getBaseName()),
it.getFile(), &table, xmlFlags);
- if (err == NO_ERROR) {
+ // Only verify IDs if there was no error and the file is non-empty.
+ if (err == NO_ERROR && it.getFile()->hasData()) {
ResXMLTree block;
block.setTo(it.getFile()->getData(), it.getFile()->getSize(), true);
checkForIds(src, block);
@@ -1550,7 +1551,7 @@
String8 src = it.getFile()->getPrintableSource();
err = compileXmlFile(bundle, assets, String16(it.getBaseName()),
it.getFile(), &table, xmlFlags);
- if (err == NO_ERROR) {
+ if (err == NO_ERROR && it.getFile()->hasData()) {
ResXMLTree block;
block.setTo(it.getFile()->getData(), it.getFile()->getSize(), true);
checkForIds(src, block);
@@ -1598,7 +1599,7 @@
err = compileXmlFile(bundle, assets, workItem.resourceName, workItem.xmlRoot,
workItem.file, &table, xmlCompilationFlags);
- if (err == NO_ERROR) {
+ if (err == NO_ERROR && workItem.file->hasData()) {
assets->addResource(workItem.resPath.getPathLeaf(),
workItem.resPath,
workItem.file,
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 391aa47..221f3c2 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -78,6 +78,17 @@
ResourceTable* table,
int options)
{
+ if (table->versionForCompat(bundle, resourceName, target, root)) {
+ // The file was versioned, so stop processing here.
+ // The resource entry has already been removed and the new one added.
+ // Remove the assets entry.
+ sp<AaptDir> resDir = assets->getDirs().valueFor(String8("res"));
+ sp<AaptDir> dir = resDir->getDirs().valueFor(target->getGroupEntry().toDirName(
+ target->getResourceType()));
+ dir->removeFile(target->getPath().getPathLeaf());
+ return NO_ERROR;
+ }
+
if ((options&XML_COMPILE_STRIP_WHITESPACE) != 0) {
root->removeWhitespace(true, NULL);
} else if ((options&XML_COMPILE_COMPACT_WHITESPACE) != 0) {
@@ -4758,6 +4769,77 @@
return false;
}
+bool ResourceTable::versionForCompat(const Bundle* bundle, const String16& resourceName,
+ const sp<AaptFile>& target, const sp<XMLNode>& root) {
+ XMLNode* node = root.get();
+ while (node->getType() != XMLNode::TYPE_ELEMENT) {
+ // We're assuming the root element is what we're looking for, which can only be under a
+ // bunch of namespace declarations.
+ if (node->getChildren().size() != 1) {
+ // Not sure what to do, bail.
+ return false;
+ }
+ node = node->getChildren().itemAt(0).get();
+ }
+
+ if (node->getElementNamespace().size() != 0) {
+ // Not something we care about.
+ return false;
+ }
+
+ int versionedSdk = 0;
+ if (node->getElementName() == String16("adaptive-icon")) {
+ versionedSdk = SDK_O;
+ }
+
+ const int minSdkVersion = getMinSdkVersion(bundle);
+ const ConfigDescription config(target->getGroupEntry().toParams());
+ if (versionedSdk <= minSdkVersion || versionedSdk <= config.sdkVersion) {
+ return false;
+ }
+
+ sp<ConfigList> cl = getConfigList(String16(mAssets->getPackage()),
+ String16(target->getResourceType()), resourceName);
+ if (!shouldGenerateVersionedResource(cl, config, versionedSdk)) {
+ return false;
+ }
+
+ // Remove the original entry.
+ cl->removeEntry(config);
+
+ // We need to wholesale version this file.
+ ConfigDescription newConfig(config);
+ newConfig.sdkVersion = versionedSdk;
+ sp<AaptFile> newFile = new AaptFile(target->getSourceFile(),
+ AaptGroupEntry(newConfig), target->getResourceType());
+ String8 resPath = String8::format("res/%s/%s.xml",
+ newFile->getGroupEntry().toDirName(target->getResourceType()).string(),
+ String8(resourceName).string());
+ resPath.convertToResPath();
+
+ // Add a resource table entry.
+ addEntry(SourcePos(),
+ String16(mAssets->getPackage()),
+ String16(target->getResourceType()),
+ resourceName,
+ String16(resPath),
+ NULL,
+ &newConfig);
+
+ // Schedule this to be compiled.
+ CompileResourceWorkItem item;
+ item.resourceName = resourceName;
+ item.resPath = resPath;
+ item.file = newFile;
+ item.xmlRoot = root->clone();
+ item.needsCompiling = false; // This step occurs after we parse/assign, so we don't need
+ // to do it again.
+ mWorkQueue.push(item);
+
+ // Now mark the old entry as deleted.
+ return true;
+}
+
status_t ResourceTable::modifyForCompat(const Bundle* bundle,
const String16& resourceName,
const sp<AaptFile>& target,
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index cf1e992..aff22d4 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -203,6 +203,9 @@
size_t numLocalResources() const;
bool hasResources() const;
+ bool versionForCompat(const Bundle* bundle, const String16& resourceName,
+ const sp<AaptFile>& file, const sp<XMLNode>& root);
+
status_t modifyForCompat(const Bundle* bundle);
status_t modifyForCompat(const Bundle* bundle,
const String16& resourceName,
@@ -431,6 +434,10 @@
mEntries.add(config, entry);
}
+ void removeEntry(const ResTable_config& config) {
+ mEntries.removeItem(config);
+ }
+
const DefaultKeyedVector<ConfigDescription, sp<Entry> >& getEntries() const { return mEntries; }
private:
const String16 mName;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
index 906ebb1..53c3f90 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
@@ -916,4 +916,9 @@
public boolean canRequestPackageInstalls() {
return false;
}
+
+ @Override
+ public ComponentName getInstantAppResolverSettingsComponent() {
+ return null;
+ }
}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 10ffd8a..1852feb 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -81,8 +81,6 @@
boolean disableNetwork(int netId);
- boolean pingSupplicant();
-
void startScan(in ScanSettings requested, in WorkSource ws);
List<ScanResult> getScanResults(String callingPackage);