Merge "Fixed bug where stack crop wasn't applied when it should"
diff --git a/core/java/android/content/pm/AppsQueryHelper.java b/core/java/android/content/pm/AppsQueryHelper.java
index a5a8e3f..084bc18 100644
--- a/core/java/android/content/pm/AppsQueryHelper.java
+++ b/core/java/android/content/pm/AppsQueryHelper.java
@@ -18,13 +18,11 @@
import android.Manifest;
import android.app.AppGlobals;
-import android.content.Context;
import android.content.Intent;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.ArraySet;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.InputMethod;
import com.android.internal.annotations.VisibleForTesting;
@@ -44,36 +42,37 @@
public static int GET_NON_LAUNCHABLE_APPS = 1;
/**
- * Return apps with {@link android.Manifest.permission#INTERACT_ACROSS_USERS} permission
+ * Return apps with {@link Manifest.permission#INTERACT_ACROSS_USERS} permission
*/
public static int GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM = 1 << 1;
/**
- * Return all input methods that are marked as default.
- * <p>When this flag is set, {@code user} specified in
- * {@link #queryApps(int, boolean, UserHandle)} must be
- * {@link UserHandle#myUserId user of the current process}.
+ * Return all input methods available for the current user.
*/
- public static int GET_DEFAULT_IMES = 1 << 2;
+ public static int GET_IMES = 1 << 2;
- private final Context mContext;
+ private final IPackageManager mPackageManager;
private List<ApplicationInfo> mAllApps;
- public AppsQueryHelper(Context context) {
- mContext = context;
+ public AppsQueryHelper(IPackageManager packageManager) {
+ mPackageManager = packageManager;
+ }
+
+ public AppsQueryHelper() {
+ this(AppGlobals.getPackageManager());
}
/**
* Return a List of all packages that satisfy a specified criteria.
* @param flags search flags. Use any combination of {@link #GET_NON_LAUNCHABLE_APPS},
- * {@link #GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM} or {@link #GET_DEFAULT_IMES}.
+ * {@link #GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM} or {@link #GET_IMES}.
* @param systemAppsOnly if true, only system apps will be returned
* @param user user, whose apps are queried
*/
public List<String> queryApps(int flags, boolean systemAppsOnly, UserHandle user) {
boolean nonLaunchableApps = (flags & GET_NON_LAUNCHABLE_APPS) > 0;
boolean interactAcrossUsers = (flags & GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM) > 0;
- boolean defaultImes = (flags & GET_DEFAULT_IMES) > 0;
+ boolean imes = (flags & GET_IMES) > 0;
if (mAllApps == null) {
mAllApps = getAllApps(user.getIdentifier());
}
@@ -113,7 +112,6 @@
}
}
}
-
if (interactAcrossUsers) {
final List<PackageInfo> packagesHoldingPermissions = getPackagesHoldingPermission(
Manifest.permission.INTERACT_ACROSS_USERS, user.getIdentifier());
@@ -129,29 +127,18 @@
}
}
- if (defaultImes) {
- if (UserHandle.myUserId() != user.getIdentifier()) {
- throw new IllegalArgumentException("Specified user handle " + user
- + " is not a user of the current process.");
- }
- List<InputMethodInfo> imis = getInputMethodList();
- int imisSize = imis.size();
- ArraySet<String> defaultImePackages = new ArraySet<>();
- for (int i = 0; i < imisSize; i++) {
- InputMethodInfo imi = imis.get(i);
- if (imi.isDefault(mContext)) {
- defaultImePackages.add(imi.getPackageName());
- }
- }
- final int allAppsSize = mAllApps.size();
- for (int i = 0; i < allAppsSize; i++) {
- final ApplicationInfo appInfo = mAllApps.get(i);
- if (systemAppsOnly && !appInfo.isSystemApp()) {
+ if (imes) {
+ final List<ResolveInfo> resolveInfos = queryIntentServicesAsUser(
+ new Intent(InputMethod.SERVICE_INTERFACE), user.getIdentifier());
+ final int resolveInfosSize = resolveInfos.size();
+
+ for (int i = 0; i < resolveInfosSize; i++) {
+ ServiceInfo serviceInfo = resolveInfos.get(i).serviceInfo;
+ if (systemAppsOnly && !serviceInfo.applicationInfo.isSystemApp()) {
continue;
}
- final String packageName = appInfo.packageName;
- if (defaultImePackages.contains(packageName)) {
- result.add(packageName);
+ if (!result.contains(serviceInfo.packageName)) {
+ result.add(serviceInfo.packageName);
}
}
}
@@ -163,9 +150,8 @@
@SuppressWarnings("unchecked")
protected List<ApplicationInfo> getAllApps(int userId) {
try {
- return AppGlobals.getPackageManager().getInstalledApplications(
- PackageManager.GET_UNINSTALLED_PACKAGES
- | PackageManager.GET_DISABLED_COMPONENTS, userId).getList();
+ return mPackageManager.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES
+ | PackageManager.GET_DISABLED_COMPONENTS, userId).getList();
} catch (RemoteException e) {
throw new IllegalStateException("Package manager has died", e);
}
@@ -173,17 +159,22 @@
@VisibleForTesting
protected List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent, int userId) {
- return mContext.getPackageManager()
- .queryIntentActivitiesAsUser(intent, PackageManager.GET_DISABLED_COMPONENTS
- | PackageManager.GET_UNINSTALLED_PACKAGES, userId);
+ try {
+ return mPackageManager.queryIntentActivities(intent, null,
+ PackageManager.GET_DISABLED_COMPONENTS
+ | PackageManager.GET_UNINSTALLED_PACKAGES,
+ userId);
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Package manager has died", e);
+ }
}
@VisibleForTesting
- @SuppressWarnings("unchecked")
- protected List<PackageInfo> getPackagesHoldingPermission(String perm, int userId) {
+ protected List<ResolveInfo> queryIntentServicesAsUser(Intent intent, int userId) {
try {
- return AppGlobals.getPackageManager().getPackagesHoldingPermissions(new String[]{perm},
- 0, userId).getList();
+ return mPackageManager.queryIntentServices(intent, null,
+ PackageManager.GET_META_DATA
+ | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, userId);
} catch (RemoteException e) {
throw new IllegalStateException("Package manager has died", e);
}
@@ -191,9 +182,13 @@
@VisibleForTesting
@SuppressWarnings("unchecked")
- protected List<InputMethodInfo> getInputMethodList() {
- InputMethodManager imm = (InputMethodManager)
- mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
- return imm.getInputMethodList();
+ protected List<PackageInfo> getPackagesHoldingPermission(String perm, int userId) {
+ try {
+ return mPackageManager.getPackagesHoldingPermissions(new String[]{perm}, 0,
+ userId).getList();
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Package manager has died", e);
+ }
}
+
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 625ed38..fdea1ba 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1638,6 +1638,8 @@
final boolean stableInsetsChanged = !mPendingStableInsets.equals(
mAttachInfo.mStableInsets);
final boolean outsetsChanged = !mPendingOutsets.equals(mAttachInfo.mOutsets);
+ final boolean surfaceSizeChanged = (relayoutResult
+ & WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED) != 0;
if (contentInsetsChanged) {
mAttachInfo.mContentInsets.set(mPendingContentInsets);
if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
@@ -1723,10 +1725,20 @@
mAttachInfo.mHardwareRenderer.isEnabled()) {
mAttachInfo.mHardwareRenderer.destroy();
}
- } else if (surfaceGenerationId != mSurface.getGenerationId() &&
- mSurfaceHolder == null && mAttachInfo.mHardwareRenderer != null) {
+ } else if ((surfaceGenerationId != mSurface.getGenerationId()
+ || surfaceSizeChanged)
+ && mSurfaceHolder == null
+ && mAttachInfo.mHardwareRenderer != null) {
mFullRedrawNeeded = true;
try {
+ // Need to do updateSurface (which leads to CanvasContext::setSurface and
+ // re-create the EGLSurface) if either the Surface changed (as indicated by
+ // generation id), or WindowManager changed the surface size. The latter is
+ // because on some chips, changing the consumer side's BufferQueue size may
+ // not take effect immediately unless we create a new EGLSurface.
+ // Note that frame size change doesn't always imply surface size change (eg.
+ // drag resizing uses fullscreen surface), need to check surfaceSizeChanged
+ // flag from WindowManager.
mAttachInfo.mHardwareRenderer.updateSurface(mSurface);
} catch (OutOfResourcesException e) {
handleOutOfResourcesException(e);
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 43d643e..c08e1b5 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -77,6 +77,11 @@
public static final int RELAYOUT_RES_DRAG_RESIZING = 0x8;
/**
+ * The window manager has changed the size of the surface from the last call.
+ */
+ public static final int RELAYOUT_RES_SURFACE_RESIZED = 0x10;
+
+ /**
* Flag for relayout: the client will be later giving
* internal insets; as a result, the window will not impact other window
* layouts until the insets are given.
diff --git a/core/jni/android_util_Log.cpp b/core/jni/android_util_Log.cpp
index 2d23cda..c89f293c 100644
--- a/core/jni/android_util_Log.cpp
+++ b/core/jni/android_util_Log.cpp
@@ -42,7 +42,9 @@
static levels_t levels;
static jboolean isLoggable(const char* tag, jint level) {
- return __android_log_is_loggable(level, tag, ANDROID_LOG_INFO);
+ return __android_log_is_loggable(level, tag,
+ ANDROID_LOG_INFO |
+ ANDROID_LOGGABLE_FLAG_NOT_WITHIN_SIGNAL);
}
static jboolean android_util_Log_isLoggable(JNIEnv* env, jobject clazz, jstring tag, jint level)
diff --git a/core/tests/coretests/src/android/content/pm/AppsQueryHelperTests.java b/core/tests/coretests/src/android/content/pm/AppsQueryHelperTests.java
index 4c9b00a..dcf2c89 100644
--- a/core/tests/coretests/src/android/content/pm/AppsQueryHelperTests.java
+++ b/core/tests/coretests/src/android/content/pm/AppsQueryHelperTests.java
@@ -33,7 +33,7 @@
@Override
public void setUp() throws Exception {
super.setUp();
- mAppsQueryHelper = new AppsQueryHelperTestable(getContext());
+ mAppsQueryHelper = new AppsQueryHelperTestable();
}
public void testQueryAppsSystemAppsOnly() {
@@ -78,33 +78,20 @@
assertEqualsIgnoreOrder(Arrays.asList("sys_app1", "sys_app3"), apps);
}
- public void testQueryAppsDefaultIme() {
- // Test query default system IMEs
- List<String> apps = mAppsQueryHelper.queryApps(AppsQueryHelper.GET_DEFAULT_IMES,
+ public void testQueryAppsImes() {
+ // Test query system IMEs
+ List<String> apps = mAppsQueryHelper.queryApps(AppsQueryHelper.GET_IMES,
true, UserHandle.of(UserHandle.myUserId()));
assertEqualsIgnoreOrder(Arrays.asList("sys_app1"), apps);
- // Test query default IMEs
- apps = mAppsQueryHelper.queryApps(AppsQueryHelper.GET_DEFAULT_IMES, false,
+ // Test query IMEs
+ apps = mAppsQueryHelper.queryApps(AppsQueryHelper.GET_IMES, false,
UserHandle.of(UserHandle.myUserId()));
assertEqualsIgnoreOrder(Arrays.asList("sys_app1", "app4"), apps);
-
- // Test that GET_DEFAULT_IMES cannot be used with a user id different from current process
- try {
- mAppsQueryHelper.queryApps(AppsQueryHelper.GET_DEFAULT_IMES, false,
- UserHandle.of(UserHandle.USER_NULL));
- fail("queryApps must fail if wrong user was passed");
- } catch (IllegalArgumentException e) {
- // OK
- }
}
private class AppsQueryHelperTestable extends AppsQueryHelper {
- public AppsQueryHelperTestable(Context context) {
- super(context);
- }
-
@Override
protected List<ApplicationInfo> getAllApps(int userId) {
final ApplicationInfo ai1 = new ApplicationInfo();
@@ -145,18 +132,19 @@
}
@Override
- protected List<InputMethodInfo> getInputMethodList() {
+ protected List<ResolveInfo> queryIntentServicesAsUser(Intent intent, int userId) {
final ResolveInfo sysApp1 = new ResolveInfo();
sysApp1.serviceInfo = new ServiceInfo();
sysApp1.serviceInfo.packageName = "sys_app1";
sysApp1.serviceInfo.name = "name";
- InputMethodInfo imi1 = new InputMethodInfo(sysApp1, false, null, null, 0, true);
+ sysApp1.serviceInfo.applicationInfo = new ApplicationInfo();
+ sysApp1.serviceInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
final ResolveInfo app4 = new ResolveInfo();
app4.serviceInfo = new ServiceInfo();
app4.serviceInfo.packageName = "app4";
app4.serviceInfo.name = "name";
- InputMethodInfo imi2 = new InputMethodInfo(app4, false, null, null, 0, true);
- return Arrays.asList(imi1, imi2);
+ app4.serviceInfo.applicationInfo = new ApplicationInfo();
+ return Arrays.asList(sysApp1, app4);
}
}
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 39d13df..64f2698 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -913,16 +913,26 @@
protected void onBoundsChange(Rect bounds) {}
/**
- * Return the intrinsic width of the underlying drawable object. Returns
- * -1 if it has no intrinsic width, such as with a solid color.
+ * Returns the drawable's intrinsic width.
+ * <p>
+ * Intrinsic width is the width at which the drawable would like to be laid
+ * out, including any inherent padding. If the drawable has no intrinsic
+ * width, such as a solid color, this method returns -1.
+ *
+ * @return the intrinsic width, or -1 if no intrinsic width
*/
public int getIntrinsicWidth() {
return -1;
}
/**
- * Return the intrinsic height of the underlying drawable object. Returns
- * -1 if it has no intrinsic height, such as with a solid color.
+ * Returns the drawable's intrinsic height.
+ * <p>
+ * Intrinsic height is the height at which the drawable would like to be
+ * laid out, including any inherent padding. If the drawable has no
+ * intrinsic height, such as a solid color, this method returns -1.
+ *
+ * @return the intrinsic height, or -1 if no intrinsic height
*/
public int getIntrinsicHeight() {
return -1;
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index 927b9c9..36d4272 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -222,12 +222,20 @@
@Override
public int getIntrinsicWidth() {
- return getDrawable().getIntrinsicWidth() + mState.mInsetLeft + mState.mInsetRight;
+ final int childWidth = getDrawable().getIntrinsicWidth();
+ if (childWidth < 0) {
+ return -1;
+ }
+ return childWidth + mState.mInsetLeft + mState.mInsetRight;
}
@Override
public int getIntrinsicHeight() {
- return getDrawable().getIntrinsicHeight() + mState.mInsetTop + mState.mInsetBottom;
+ final int childHeight = getDrawable().getIntrinsicHeight();
+ if (childHeight < 0) {
+ return -1;
+ }
+ return childHeight + mState.mInsetTop + mState.mInsetBottom;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index bf5417d..95f1eb2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -27,6 +27,7 @@
import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.provider.Settings;
import android.util.Log;
import android.view.Display;
import android.view.View;
@@ -193,6 +194,12 @@
*/
@Override
public void showRecents(boolean triggeredFromAltTab, View statusBarView) {
+ // Ensure the device has been provisioned before allowing the user to interact with
+ // recents
+ if (!isDeviceProvisioned()) {
+ return;
+ }
+
if (proxyToOverridePackage(ACTION_SHOW_RECENTS)) {
return;
}
@@ -222,6 +229,12 @@
*/
@Override
public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
+ // Ensure the device has been provisioned before allowing the user to interact with
+ // recents
+ if (!isDeviceProvisioned()) {
+ return;
+ }
+
if (proxyToOverridePackage(ACTION_HIDE_RECENTS)) {
return;
}
@@ -251,6 +264,12 @@
*/
@Override
public void toggleRecents(Display display, int layoutDirection, View statusBarView) {
+ // Ensure the device has been provisioned before allowing the user to interact with
+ // recents
+ if (!isDeviceProvisioned()) {
+ return;
+ }
+
if (proxyToOverridePackage(ACTION_TOGGLE_RECENTS)) {
return;
}
@@ -280,6 +299,12 @@
*/
@Override
public void preloadRecents() {
+ // Ensure the device has been provisioned before allowing the user to interact with
+ // recents
+ if (!isDeviceProvisioned()) {
+ return;
+ }
+
int currentUser = sSystemServicesProxy.getCurrentUser();
if (sSystemServicesProxy.isSystemUser(currentUser)) {
mImpl.preloadRecents();
@@ -302,6 +327,12 @@
@Override
public void cancelPreloadingRecents() {
+ // Ensure the device has been provisioned before allowing the user to interact with
+ // recents
+ if (!isDeviceProvisioned()) {
+ return;
+ }
+
int currentUser = sSystemServicesProxy.getCurrentUser();
if (sSystemServicesProxy.isSystemUser(currentUser)) {
mImpl.cancelPreloadingRecents();
@@ -329,11 +360,23 @@
@Override
public void showNextAffiliatedTask() {
+ // Ensure the device has been provisioned before allowing the user to interact with
+ // recents
+ if (!isDeviceProvisioned()) {
+ return;
+ }
+
mImpl.showNextAffiliatedTask();
}
@Override
public void showPrevAffiliatedTask() {
+ // Ensure the device has been provisioned before allowing the user to interact with
+ // recents
+ if (!isDeviceProvisioned()) {
+ return;
+ }
+
mImpl.showPrevAffiliatedTask();
}
@@ -456,6 +499,14 @@
}
/**
+ * @return whether this device is provisioned.
+ */
+ private boolean isDeviceProvisioned() {
+ return Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.DEVICE_PROVISIONED, 0) != 0;
+ }
+
+ /**
* Attempts to proxy the following action to the override recents package.
* @return whether the proxying was successful
*/
diff --git a/rs/java/android/renderscript/ScriptGroup.java b/rs/java/android/renderscript/ScriptGroup.java
index 54180f4..9bbacbc 100644
--- a/rs/java/android/renderscript/ScriptGroup.java
+++ b/rs/java/android/renderscript/ScriptGroup.java
@@ -278,6 +278,8 @@
public ValueAndSize(RenderScript rs, Object obj) {
if (obj instanceof Allocation) {
value = ((Allocation)obj).getID(rs);
+ // Special value for size to tell the runtime and driver that
+ // the value is an Allocation
size = -1;
} else if (obj instanceof Boolean) {
value = ((Boolean)obj).booleanValue() ? 1 : 0;
@@ -289,10 +291,10 @@
value = ((Long)obj).longValue();
size = 8;
} else if (obj instanceof Float) {
- value = ((Float)obj).longValue();
+ value = Float.floatToRawIntBits(((Float)obj).floatValue());
size = 4;
} else if (obj instanceof Double) {
- value = ((Double)obj).longValue();
+ value = Double.doubleToRawLongBits(((Double)obj).doubleValue());
size = 8;
}
}
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index be7071e..113241d 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -393,7 +393,6 @@
size_t numValues, numDependencies;
RsScriptFieldID* fieldIDs;
- uintptr_t* values;
RsClosure* depClosures;
RsScriptFieldID* depFieldIDs;
@@ -430,15 +429,6 @@
fieldIDs[i] = (RsScriptFieldID)jFieldIDs[i];
}
- values = (uintptr_t*)alloca(sizeof(uintptr_t) * numValues);
- if (values == nullptr) {
- goto exit;
- }
-
- for (size_t i = 0; i < numValues; i++) {
- values[i] = (uintptr_t)jValues[i];
- }
-
depClosures = (RsClosure*)alloca(sizeof(RsClosure) * numDependencies);
if (depClosures == nullptr) {
goto exit;
@@ -459,7 +449,7 @@
ret = (jlong)(uintptr_t)rsClosureCreate(
(RsContext)con, (RsScriptKernelID)kernelID, (RsAllocation)returnValue,
- fieldIDs, numValues, values, numValues,
+ fieldIDs, numValues, jValues, numValues,
(int*)jSizes, numValues,
depClosures, numDependencies,
depFieldIDs, numDependencies);
@@ -511,7 +501,6 @@
size_t numValues;
RsScriptFieldID* fieldIDs;
- uintptr_t* values;
if (fieldIDs_length != values_length || values_length != sizes_length) {
ALOGE("Unmatched field IDs, values, and sizes in closure creation.");
@@ -534,18 +523,9 @@
fieldIDs[i] = (RsScriptFieldID)jFieldIDs[i];
}
- values = (uintptr_t*)alloca(sizeof(uintptr_t) * numValues);
- if (values == nullptr) {
- goto exit;
- }
-
- for (size_t i = 0; i < numValues; i++) {
- values[i] = (uintptr_t)jValues[i];
- }
-
ret = (jlong)(uintptr_t)rsInvokeClosureCreate(
(RsContext)con, (RsScriptInvokeID)invokeID, jParams, jParamLength,
- fieldIDs, numValues, values, numValues,
+ fieldIDs, numValues, jValues, numValues,
(int*)jSizes, numValues);
exit:
@@ -561,15 +541,17 @@
static void
nClosureSetArg(JNIEnv *_env, jobject _this, jlong con, jlong closureID,
jint index, jlong value, jint size) {
+ // Size is signed with -1 indicating the value is an Allocation
rsClosureSetArg((RsContext)con, (RsClosure)closureID, (uint32_t)index,
- (uintptr_t)value, (size_t)size);
+ (uintptr_t)value, size);
}
static void
nClosureSetGlobal(JNIEnv *_env, jobject _this, jlong con, jlong closureID,
jlong fieldID, jlong value, jint size) {
+ // Size is signed with -1 indicating the value is an Allocation
rsClosureSetGlobal((RsContext)con, (RsClosure)closureID,
- (RsScriptFieldID)fieldID, (uintptr_t)value, (size_t)size);
+ (RsScriptFieldID)fieldID, (int64_t)value, size);
}
static long
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index cde126a..566065c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -12102,8 +12102,6 @@
}
}
- enableSystemUserApps();
-
// Start up initial activity.
mBooting = true;
startHomeActivityLocked(currentUserId, "systemReady");
@@ -12155,43 +12153,6 @@
}
}
- private void enableSystemUserApps() {
- // For system user, enable apps based on the following conditions:
- // - app is whitelisted; or has no launcher icons; or has INTERACT_ACROSS_USERS permission
- // - app is not in the blacklist
- if (UserManager.isSplitSystemUser()) {
- AppsQueryHelper queryHelper = new AppsQueryHelper(mContext);
- Set<String> enableApps = new HashSet<>();
- enableApps.addAll(queryHelper.queryApps(AppsQueryHelper.GET_NON_LAUNCHABLE_APPS
- | AppsQueryHelper.GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM
- | AppsQueryHelper.GET_DEFAULT_IMES,
- /* systemAppsOnly */ true, UserHandle.SYSTEM));
- ArraySet<String> wlApps = SystemConfig.getInstance().getSystemUserWhitelistedApps();
- enableApps.addAll(wlApps);
- ArraySet<String> blApps = SystemConfig.getInstance().getSystemUserBlacklistedApps();
- enableApps.removeAll(blApps);
-
- List<String> systemApps = queryHelper.queryApps(0, /* systemAppsOnly */ true,
- UserHandle.SYSTEM);
- final int systemAppsSize = systemApps.size();
- for (int i = 0; i < systemAppsSize; i++) {
- String pName = systemApps.get(i);
- boolean enable = enableApps.contains(pName);
- try {
- if (enable) {
- AppGlobals.getPackageManager().installExistingPackageAsUser(pName,
- UserHandle.USER_SYSTEM);
- } else {
- AppGlobals.getPackageManager().deletePackageAsUser(pName, null,
- UserHandle.USER_SYSTEM, PackageManager.DELETE_SYSTEM_APP);
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Error occured when processing package " + pName, e);
- }
- }
- }
- }
-
private boolean makeAppCrashingLocked(ProcessRecord app,
String shortMsg, String longMsg, String stackTrace) {
app.crashing = true;
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 853a55c..9896ec5 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1338,7 +1338,12 @@
return topHomeActivity == null || !topHomeActivity.isHomeActivity();
}
- final int belowFocusedIndex = mStacks.indexOf(focusedStack) - 1;
+ // Find the first stack below focused stack that actually got something visible.
+ int belowFocusedIndex = mStacks.indexOf(focusedStack) - 1;
+ while (belowFocusedIndex >= 0 &&
+ mStacks.get(belowFocusedIndex).topRunningActivityLocked() == null) {
+ belowFocusedIndex--;
+ }
if ((focusedStackId == DOCKED_STACK_ID || focusedStackId == PINNED_STACK_ID)
&& stackIndex == belowFocusedIndex) {
// Stacks directly behind the docked or pinned stack are always visible.
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 4fc8454..13d3ee1 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -3340,6 +3340,12 @@
return;
}
+ if (task.stack != null && task.stack.mStackId == stackId) {
+ // You are already in the right stack silly...
+ Slog.i(TAG, "moveTaskToStack: taskId=" + taskId + " already in stackId=" + stackId);
+ return;
+ }
+
final ActivityRecord topActivity = task.getTopActivity();
if (StackId.preserveWindowOnTaskMove(stackId) && topActivity != null) {
// We are about to relaunch the activity because its configuration changed due to
@@ -3356,15 +3362,13 @@
// Make sure the task has the appropriate bounds/size for the stack it is in.
if (stackId == FULLSCREEN_WORKSPACE_STACK_ID && task.mBounds != null) {
- resizeTaskLocked(task, stack.mBounds,
- RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS);
+ resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS);
} else if (stackId == FREEFORM_WORKSPACE_STACK_ID
&& task.mBounds == null && task.mLastNonFullscreenBounds != null) {
resizeTaskLocked(task, task.mLastNonFullscreenBounds,
RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS);
} else if (stackId == DOCKED_STACK_ID || stackId == PINNED_STACK_ID) {
- resizeTaskLocked(task, stack.mBounds,
- RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS);
+ resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS);
}
// The task might have already been running and its visibility needs to be synchronized with
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index bb805c1..c152514 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -105,6 +105,7 @@
import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.pm.AppsQueryHelper;
import android.content.pm.FeatureInfo;
import android.content.pm.IOnPermissionsChangeListener;
import android.content.pm.IPackageDataObserver;
@@ -1810,10 +1811,48 @@
boolean factoryTest, boolean onlyCore) {
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
+ m.enableSystemUserApps();
ServiceManager.addService("package", m);
return m;
}
+ private void enableSystemUserApps() {
+ if (!UserManager.isSplitSystemUser()) {
+ return;
+ }
+ // For system user, enable apps based on the following conditions:
+ // - app is whitelisted or belong to one of these groups:
+ // -- system app which has no launcher icons
+ // -- system app which has INTERACT_ACROSS_USERS permission
+ // -- system IME app
+ // - app is not in the blacklist
+ AppsQueryHelper queryHelper = new AppsQueryHelper(this);
+ Set<String> enableApps = new ArraySet<>();
+ enableApps.addAll(queryHelper.queryApps(AppsQueryHelper.GET_NON_LAUNCHABLE_APPS
+ | AppsQueryHelper.GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM
+ | AppsQueryHelper.GET_IMES, /* systemAppsOnly */ true, UserHandle.SYSTEM));
+ ArraySet<String> wlApps = SystemConfig.getInstance().getSystemUserWhitelistedApps();
+ enableApps.addAll(wlApps);
+ ArraySet<String> blApps = SystemConfig.getInstance().getSystemUserBlacklistedApps();
+ enableApps.removeAll(blApps);
+
+ List<String> systemApps = queryHelper.queryApps(0, /* systemAppsOnly */ true,
+ UserHandle.SYSTEM);
+ final int systemAppsSize = systemApps.size();
+ synchronized (mPackages) {
+ for (int i = 0; i < systemAppsSize; i++) {
+ String pName = systemApps.get(i);
+ PackageSetting pkgSetting = mSettings.mPackages.get(pName);
+ // Should not happen, but we shouldn't be failing if it does
+ if (pkgSetting == null) {
+ continue;
+ }
+ boolean installed = enableApps.contains(pName);
+ pkgSetting.setInstalled(installed, UserHandle.USER_SYSTEM);
+ }
+ }
+ }
+
static String[] splitString(String str, char sep) {
int count = 1;
int i = 0;
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index ac79b36..97713fc 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -54,6 +54,15 @@
@Override
public void onReceive(Context context, Intent intent) {
+ // When a package is replaced we will receive two intents, one representing the
+ // removal of the old package and one representing the addition of the new
+ // package. We here ignore the intent representing the removed package to make
+ // sure we don't change WebView provider twice.
+ if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)
+ && intent.getExtras().getBoolean(Intent.EXTRA_REPLACING)) {
+ return;
+ }
+
for (String packageName : WebViewFactory.getWebViewPackageNames()) {
String webviewPackage = "package:" + packageName;
@@ -73,7 +82,8 @@
}
};
IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+ filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addDataScheme("package");
getContext().registerReceiver(mWebViewUpdatedReceiver, filter);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 89f0b83..5737d479 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2725,6 +2725,8 @@
WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
}
+ final int oldSurfaceResizeGeneration = winAnimator.mSurfaceResizeGeneration;
+
win.setDisplayLayoutNeeded();
win.mGivenInsetsPending = (flags&WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0;
configChanged = updateOrientationFromAppTokensLocked(false);
@@ -2737,6 +2739,9 @@
if (win.mAppToken != null) {
win.mAppToken.updateReportedVisibilityLocked();
}
+ if (winAnimator.mSurfaceResizeGeneration != oldSurfaceResizeGeneration) {
+ result |= WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED;
+ }
outFrame.set(win.mCompatFrame);
outOverscanInsets.set(win.mOverscanInsets);
outContentInsets.set(win.mContentInsets);
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 441a2ab..5f50144 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -99,6 +99,7 @@
* we must tell them application to resize (and thus redraw itself).
*/
boolean mSurfaceResized;
+ int mSurfaceResizeGeneration;
WindowSurfaceController mSurfaceController;
private WindowSurfaceController mPendingDestroySurface;
@@ -1188,6 +1189,7 @@
recoveringMemory);
if (mSurfaceResized) {
+ mSurfaceResizeGeneration++;
mAnimator.setPendingLayoutChanges(w.getDisplayId(),
WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
w.applyDimLayerIfNeeded();
diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp
index deafe20..73d8585 100644
--- a/tools/aapt2/ResourceTable.cpp
+++ b/tools/aapt2/ResourceTable.cpp
@@ -190,22 +190,32 @@
bool ResourceTable::addResource(const ResourceNameRef& name, const ConfigDescription& config,
std::unique_ptr<Value> value, IDiagnostics* diag) {
- return addResourceImpl(name, {}, config, std::move(value), kValidNameChars, diag);
+ return addResourceImpl(name, {}, config, std::move(value), kValidNameChars,
+ resolveValueCollision, diag);
}
bool ResourceTable::addResource(const ResourceNameRef& name, const ResourceId resId,
const ConfigDescription& config, std::unique_ptr<Value> value,
IDiagnostics* diag) {
- return addResourceImpl(name, resId, config, std::move(value), kValidNameChars, diag);
+ return addResourceImpl(name, resId, config, std::move(value), kValidNameChars,
+ resolveValueCollision, diag);
}
bool ResourceTable::addFileReference(const ResourceNameRef& name, const ConfigDescription& config,
const Source& source, const StringPiece16& path,
IDiagnostics* diag) {
+ return addFileReference(name, config, source, path, resolveValueCollision, diag);
+}
+
+bool ResourceTable::addFileReference(const ResourceNameRef& name, const ConfigDescription& config,
+ const Source& source, const StringPiece16& path,
+ std::function<int(Value*,Value*)> conflictResolver,
+ IDiagnostics* diag) {
std::unique_ptr<FileReference> fileRef = util::make_unique<FileReference>(
stringPool.makeRef(path));
fileRef->setSource(source);
- return addResourceImpl(name, ResourceId{}, config, std::move(fileRef), kValidNameChars, diag);
+ return addResourceImpl(name, ResourceId{}, config, std::move(fileRef), kValidNameChars,
+ conflictResolver, diag);
}
bool ResourceTable::addResourceAllowMangled(const ResourceNameRef& name,
@@ -213,7 +223,7 @@
std::unique_ptr<Value> value,
IDiagnostics* diag) {
return addResourceImpl(name, ResourceId{}, config, std::move(value), kValidNameMangledChars,
- diag);
+ resolveValueCollision, diag);
}
bool ResourceTable::addResourceAllowMangled(const ResourceNameRef& name,
@@ -221,12 +231,17 @@
const ConfigDescription& config,
std::unique_ptr<Value> value,
IDiagnostics* diag) {
- return addResourceImpl(name, id, config, std::move(value), kValidNameMangledChars, diag);
+ return addResourceImpl(name, id, config, std::move(value), kValidNameMangledChars,
+ resolveValueCollision, diag);
}
-bool ResourceTable::addResourceImpl(const ResourceNameRef& name, const ResourceId resId,
- const ConfigDescription& config, std::unique_ptr<Value> value,
- const char16_t* validChars, IDiagnostics* diag) {
+bool ResourceTable::addResourceImpl(const ResourceNameRef& name,
+ const ResourceId resId,
+ const ConfigDescription& config,
+ std::unique_ptr<Value> value,
+ const char16_t* validChars,
+ std::function<int(Value*,Value*)> conflictResolver,
+ IDiagnostics* diag) {
assert(value && "value can't be nullptr");
assert(diag && "diagnostics can't be nullptr");
@@ -289,7 +304,7 @@
// This resource did not exist before, add it.
entry->values.insert(iter, ResourceConfigValue{ config, std::move(value) });
} else {
- int collisionResult = resolveValueCollision(iter->value.get(), value.get());
+ int collisionResult = conflictResolver(iter->value.get(), value.get());
if (collisionResult > 0) {
// Take the incoming value.
iter->value = std::move(value);
diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h
index 980504b..6b7b07e 100644
--- a/tools/aapt2/ResourceTable.h
+++ b/tools/aapt2/ResourceTable.h
@@ -163,7 +163,12 @@
IDiagnostics* diag);
bool addFileReference(const ResourceNameRef& name, const ConfigDescription& config,
- const Source& source, const StringPiece16& path, IDiagnostics* diag);
+ const Source& source, const StringPiece16& path,
+ IDiagnostics* diag);
+
+ bool addFileReference(const ResourceNameRef& name, const ConfigDescription& config,
+ const Source& source, const StringPiece16& path,
+ std::function<int(Value*,Value*)> conflictResolver, IDiagnostics* diag);
/**
* Same as addResource, but doesn't verify the validity of the name. This is used
@@ -221,9 +226,14 @@
private:
ResourceTablePackage* findOrCreatePackage(const StringPiece16& name);
- bool addResourceImpl(const ResourceNameRef& name, ResourceId resId,
- const ConfigDescription& config, std::unique_ptr<Value> value,
- const char16_t* validChars, IDiagnostics* diag);
+ bool addResourceImpl(const ResourceNameRef& name,
+ ResourceId resId,
+ const ConfigDescription& config,
+ std::unique_ptr<Value> value,
+ const char16_t* validChars,
+ std::function<int(Value*,Value*)> conflictResolver,
+ IDiagnostics* diag);
+
bool setSymbolStateImpl(const ResourceNameRef& name, ResourceId resId,
const Symbol& symbol, const char16_t* validChars, IDiagnostics* diag);
};
diff --git a/tools/aapt2/link/Link.cpp b/tools/aapt2/link/Link.cpp
index 9ce3734..93f2dc6f 100644
--- a/tools/aapt2/link/Link.cpp
+++ b/tools/aapt2/link/Link.cpp
@@ -48,6 +48,7 @@
std::string outputPath;
std::string manifestPath;
std::vector<std::string> includePaths;
+ std::vector<std::string> overlayFiles;
Maybe<std::string> generateJavaClassPath;
std::vector<std::string> extraJavaPackages;
Maybe<std::string> generateProguardRulesPath;
@@ -88,9 +89,11 @@
}
};
-struct LinkCommand {
- LinkOptions mOptions;
- LinkContext mContext;
+class LinkCommand {
+public:
+ LinkCommand(const LinkOptions& options) :
+ mOptions(options), mContext(), mFinalTable() {
+ }
std::string buildResourceFileName(const ResourceFile& resFile) {
std::stringstream out;
@@ -117,8 +120,7 @@
AssetManagerSymbolTableBuilder builder;
for (const std::string& path : mOptions.includePaths) {
if (mOptions.verbose) {
- mContext.getDiagnostics()->note(
- DiagMessage(Source{ path }) << "loading include path");
+ mContext.getDiagnostics()->note(DiagMessage(path) << "loading include path");
}
std::unique_ptr<android::AssetManager> assetManager =
@@ -126,7 +128,7 @@
int32_t cookie = 0;
if (!assetManager->addAssetPath(android::String8(path.data(), path.size()), &cookie)) {
mContext.getDiagnostics()->error(
- DiagMessage(Source{ path }) << "failed to load include path");
+ DiagMessage(path) << "failed to load include path");
return {};
}
builder.add(std::move(assetManager));
@@ -141,12 +143,12 @@
std::string errorStr;
Maybe<android::FileMap> map = file::mmapPath(input, &errorStr);
if (!map) {
- mContext.getDiagnostics()->error(DiagMessage(Source{ input }) << errorStr);
+ mContext.getDiagnostics()->error(DiagMessage(input) << errorStr);
return {};
}
std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
- BinaryResourceParser parser(&mContext, table.get(), Source{ input },
+ BinaryResourceParser parser(&mContext, table.get(), Source(input),
map.value().getDataPtr(), map.value().getDataLength());
if (!parser.parse()) {
return {};
@@ -160,11 +162,11 @@
std::unique_ptr<XmlResource> loadXml(const std::string& path) {
std::ifstream fin(path, std::ifstream::binary);
if (!fin) {
- mContext.getDiagnostics()->error(DiagMessage(Source{ path }) << strerror(errno));
+ mContext.getDiagnostics()->error(DiagMessage(path) << strerror(errno));
return {};
}
- return xml::inflate(&fin, mContext.getDiagnostics(), Source{ path });
+ return xml::inflate(&fin, mContext.getDiagnostics(), Source(path));
}
/**
@@ -255,9 +257,9 @@
return {};
}
- bool verifyNoExternalPackages(ResourceTable* table) {
+ bool verifyNoExternalPackages() {
bool error = false;
- for (const auto& package : table->packages) {
+ for (const auto& package : mFinalTable.packages) {
if (mContext.getCompilationPackage() != package->name ||
!package->id || package->id.value() != mContext.getPackageId()) {
// We have a package that is not related to the one we're building!
@@ -401,6 +403,103 @@
return true;
}
+ bool mergeStaticLibrary(const std::string& input) {
+ // TODO(adamlesinski): Load resources from a static library APK and merge the table into
+ // TableMerger.
+ mContext.getDiagnostics()->warn(DiagMessage()
+ << "linking static libraries not supported yet: "
+ << input);
+ return true;
+ }
+
+ bool mergeResourceTable(const std::string& input, bool override) {
+ if (mOptions.verbose) {
+ mContext.getDiagnostics()->note(DiagMessage() << "linking " << input);
+ }
+
+ std::unique_ptr<ResourceTable> table = loadTable(input);
+ if (!table) {
+ return false;
+ }
+
+ if (!mTableMerger->merge(Source(input), table.get(), override)) {
+ return false;
+ }
+ return true;
+ }
+
+ bool mergeCompiledFile(const std::string& input, ResourceFile&& file, bool override) {
+ if (file.name.package.empty()) {
+ file.name.package = mContext.getCompilationPackage().toString();
+ }
+
+ ResourceNameRef resName = file.name;
+
+ Maybe<ResourceName> mangledName = mContext.getNameMangler()->mangleName(file.name);
+ if (mangledName) {
+ resName = mangledName.value();
+ }
+
+ std::function<int(Value*,Value*)> resolver;
+ if (override) {
+ resolver = [](Value* a, Value* b) -> int {
+ int result = ResourceTable::resolveValueCollision(a, b);
+ if (result == 0) {
+ // Always accept the new value if it would normally conflict (override).
+ result = 1;
+ }
+ return result;
+ };
+ } else {
+ // Otherwise use the default resolution.
+ resolver = ResourceTable::resolveValueCollision;
+ }
+
+ // Add this file to the table.
+ if (!mFinalTable.addFileReference(resName, file.config, file.source,
+ util::utf8ToUtf16(buildResourceFileName(file)),
+ resolver, mContext.getDiagnostics())) {
+ return false;
+ }
+
+ // Add the exports of this file to the table.
+ for (SourcedResourceName& exportedSymbol : file.exportedSymbols) {
+ if (exportedSymbol.name.package.empty()) {
+ exportedSymbol.name.package = mContext.getCompilationPackage().toString();
+ }
+
+ ResourceNameRef resName = exportedSymbol.name;
+
+ Maybe<ResourceName> mangledName = mContext.getNameMangler()->mangleName(
+ exportedSymbol.name);
+ if (mangledName) {
+ resName = mangledName.value();
+ }
+
+ std::unique_ptr<Id> id = util::make_unique<Id>();
+ id->setSource(file.source.withLine(exportedSymbol.line));
+ bool result = mFinalTable.addResourceAllowMangled(resName, {}, std::move(id),
+ mContext.getDiagnostics());
+ if (!result) {
+ return false;
+ }
+ }
+
+ mFilesToProcess[resName.toResourceName()] = FileToProcess{ Source(input), std::move(file) };
+ return true;
+ }
+
+ bool processFile(const std::string& input, bool override) {
+ if (util::stringEndsWith<char>(input, ".apk")) {
+ return mergeStaticLibrary(input);
+ } else if (util::stringEndsWith<char>(input, ".arsc.flat")) {
+ return mergeResourceTable(input, override);
+ } else if (Maybe<ResourceFile> maybeF = loadFileExportHeader(input)) {
+ return mergeCompiledFile(input, std::move(maybeF.value()), override);
+ }
+ return false;
+ }
+
int run(const std::vector<std::string>& inputFiles) {
// Load the AndroidManifest.xml
std::unique_ptr<XmlResource> manifestXml = loadXml(mOptions.manifestPath);
@@ -438,82 +537,25 @@
return 1;
}
+ mTableMerger = util::make_unique<TableMerger>(&mContext, &mFinalTable);
+
if (mOptions.verbose) {
mContext.getDiagnostics()->note(
DiagMessage() << "linking package '" << mContext.mCompilationPackage << "' "
<< "with package ID " << std::hex << (int) mContext.mPackageId);
}
- ResourceTable mergedTable;
- TableMerger tableMerger(&mContext, &mergedTable);
-
- struct FilesToProcess {
- Source source;
- ResourceFile file;
- };
-
bool error = false;
- std::queue<FilesToProcess> filesToProcess;
+
for (const std::string& input : inputFiles) {
- if (util::stringEndsWith<char>(input, ".apk")) {
- // TODO(adamlesinski): Load resources from a static library APK
- // Merge the table into TableMerger.
+ if (!processFile(input, false)) {
+ error = true;
+ }
+ }
- } else if (util::stringEndsWith<char>(input, ".arsc.flat")) {
- if (mOptions.verbose) {
- mContext.getDiagnostics()->note(DiagMessage() << "linking " << input);
- }
-
- std::unique_ptr<ResourceTable> table = loadTable(input);
- if (!table) {
- return 1;
- }
-
- if (!tableMerger.merge(Source(input), table.get())) {
- return 1;
- }
-
- } else {
- // Extract the exported IDs here so we can build the resource table.
- if (Maybe<ResourceFile> maybeF = loadFileExportHeader(input)) {
- ResourceFile& f = maybeF.value();
-
- if (f.name.package.empty()) {
- f.name.package = mContext.getCompilationPackage().toString();
- }
-
- Maybe<ResourceName> mangledName = mContext.getNameMangler()->mangleName(f.name);
-
- // Add this file to the table.
- if (!mergedTable.addFileReference(mangledName ? mangledName.value() : f.name,
- f.config, f.source,
- util::utf8ToUtf16(buildResourceFileName(f)),
- mContext.getDiagnostics())) {
- error = true;
- }
-
- // Add the exports of this file to the table.
- for (SourcedResourceName& exportedSymbol : f.exportedSymbols) {
- if (exportedSymbol.name.package.empty()) {
- exportedSymbol.name.package = mContext.getCompilationPackage()
- .toString();
- }
-
- Maybe<ResourceName> mangledName = mContext.getNameMangler()->mangleName(
- exportedSymbol.name);
- std::unique_ptr<Id> id = util::make_unique<Id>();
- id->setSource(f.source.withLine(exportedSymbol.line));
- if (!mergedTable.addResourceAllowMangled(
- mangledName ? mangledName.value() : exportedSymbol.name,
- {}, std::move(id), mContext.getDiagnostics())) {
- error = true;
- }
- }
-
- filesToProcess.push(FilesToProcess{ Source(input), std::move(f) });
- } else {
- return 1;
- }
+ for (const std::string& input : mOptions.overlayFiles) {
+ if (!processFile(input, true)) {
+ error = true;
}
}
@@ -522,13 +564,13 @@
return 1;
}
- if (!verifyNoExternalPackages(&mergedTable)) {
+ if (!verifyNoExternalPackages()) {
return 1;
}
if (!mOptions.staticLib) {
PrivateAttributeMover mover;
- if (!mover.consume(&mContext, &mergedTable)) {
+ if (!mover.consume(&mContext, &mFinalTable)) {
mContext.getDiagnostics()->error(
DiagMessage() << "failed moving private attributes");
return 1;
@@ -537,22 +579,22 @@
{
IdAssigner idAssigner;
- if (!idAssigner.consume(&mContext, &mergedTable)) {
+ if (!idAssigner.consume(&mContext, &mFinalTable)) {
mContext.getDiagnostics()->error(DiagMessage() << "failed assigning IDs");
return 1;
}
}
- mContext.mNameMangler = util::make_unique<NameMangler>(
- NameManglerPolicy{ mContext.mCompilationPackage, tableMerger.getMergedPackages() });
+ mContext.mNameMangler = util::make_unique<NameMangler>(NameManglerPolicy{
+ mContext.mCompilationPackage, mTableMerger->getMergedPackages() });
mContext.mSymbols = JoinedSymbolTableBuilder()
- .addSymbolTable(util::make_unique<SymbolTableWrapper>(&mergedTable))
+ .addSymbolTable(util::make_unique<SymbolTableWrapper>(&mFinalTable))
.addSymbolTable(std::move(mContext.mSymbols))
.build();
{
ReferenceLinker linker;
- if (!linker.consume(&mContext, &mergedTable)) {
+ if (!linker.consume(&mContext, &mFinalTable)) {
mContext.getDiagnostics()->error(DiagMessage() << "failed linking references");
return 1;
}
@@ -598,20 +640,20 @@
}
}
- for (; !filesToProcess.empty(); filesToProcess.pop()) {
- FilesToProcess& f = filesToProcess.front();
- if (f.file.name.type != ResourceType::kRaw &&
- util::stringEndsWith<char>(f.source.path, ".xml.flat")) {
+ for (auto& pair : mFilesToProcess) {
+ FileToProcess& file = pair.second;
+ if (file.file.name.type != ResourceType::kRaw &&
+ util::stringEndsWith<char>(file.source.path, ".xml.flat")) {
if (mOptions.verbose) {
- mContext.getDiagnostics()->note(DiagMessage() << "linking " << f.source.path);
+ mContext.getDiagnostics()->note(DiagMessage() << "linking " << file.source.path);
}
- std::unique_ptr<XmlResource> xmlRes = loadBinaryXmlSkipFileExport(f.source.path);
+ std::unique_ptr<XmlResource> xmlRes = loadBinaryXmlSkipFileExport(file.source.path);
if (!xmlRes) {
return 1;
}
- xmlRes->file = std::move(f.file);
+ xmlRes->file = std::move(file.file);
XmlReferenceLinker xmlLinker;
if (xmlLinker.consume(&mContext, xmlRes.get())) {
@@ -631,7 +673,7 @@
}
if (!mOptions.noAutoVersion) {
- Maybe<ResourceTable::SearchResult> result = mergedTable.findResource(
+ Maybe<ResourceTable::SearchResult> result = mFinalTable.findResource(
xmlRes->file.name);
for (int sdkLevel : xmlLinker.getSdkLevels()) {
if (sdkLevel > xmlRes->file.config.sdkVersion &&
@@ -639,7 +681,7 @@
xmlRes->file.config,
sdkLevel)) {
xmlRes->file.config.sdkVersion = sdkLevel;
- if (!mergedTable.addFileReference(xmlRes->file.name,
+ if (!mFinalTable.addFileReference(xmlRes->file.name,
xmlRes->file.config,
xmlRes->file.source,
util::utf8ToUtf16(
@@ -662,10 +704,11 @@
}
} else {
if (mOptions.verbose) {
- mContext.getDiagnostics()->note(DiagMessage() << "copying " << f.source.path);
+ mContext.getDiagnostics()->note(DiagMessage() << "copying "
+ << file.source.path);
}
- if (!copyFileToArchive(f.source.path, buildResourceFileName(f.file), 0,
+ if (!copyFileToArchive(file.source.path, buildResourceFileName(file.file), 0,
archiveWriter.get())) {
error = true;
}
@@ -679,13 +722,13 @@
if (!mOptions.noAutoVersion) {
AutoVersioner versioner;
- if (!versioner.consume(&mContext, &mergedTable)) {
+ if (!versioner.consume(&mContext, &mFinalTable)) {
mContext.getDiagnostics()->error(DiagMessage() << "failed versioning styles");
return 1;
}
}
- if (!flattenTable(&mergedTable, archiveWriter.get())) {
+ if (!flattenTable(&mFinalTable, archiveWriter.get())) {
mContext.getDiagnostics()->error(DiagMessage() << "failed to write resources.arsc");
return 1;
}
@@ -704,7 +747,7 @@
// to the original package, and private and public symbols to the private package.
options.types = JavaClassGeneratorOptions::SymbolTypes::kPublic;
- if (!writeJavaFile(&mergedTable, mContext.getCompilationPackage(),
+ if (!writeJavaFile(&mFinalTable, mContext.getCompilationPackage(),
mContext.getCompilationPackage(), options)) {
return 1;
}
@@ -713,12 +756,12 @@
outputPackage = mOptions.privateSymbols.value();
}
- if (!writeJavaFile(&mergedTable, actualPackage, outputPackage, options)) {
+ if (!writeJavaFile(&mFinalTable, actualPackage, outputPackage, options)) {
return 1;
}
for (std::string& extraPackage : mOptions.extraJavaPackages) {
- if (!writeJavaFile(&mergedTable, actualPackage, util::utf8ToUtf16(extraPackage),
+ if (!writeJavaFile(&mFinalTable, actualPackage, util::utf8ToUtf16(extraPackage),
options)) {
return 1;
}
@@ -732,10 +775,10 @@
}
if (mOptions.verbose) {
- Debug::printTable(&mergedTable);
- for (; !tableMerger.getFileMergeQueue()->empty();
- tableMerger.getFileMergeQueue()->pop()) {
- const FileToMerge& f = tableMerger.getFileMergeQueue()->front();
+ Debug::printTable(&mFinalTable);
+ for (; !mTableMerger->getFileMergeQueue()->empty();
+ mTableMerger->getFileMergeQueue()->pop()) {
+ const FileToMerge& f = mTableMerger->getFileMergeQueue()->front();
mContext.getDiagnostics()->note(
DiagMessage() << f.srcPath << " -> " << f.dstPath << " from (0x"
<< std::hex << (uintptr_t) f.srcTable << std::dec);
@@ -744,6 +787,18 @@
return 0;
}
+
+private:
+ LinkOptions mOptions;
+ LinkContext mContext;
+ ResourceTable mFinalTable;
+ std::unique_ptr<TableMerger> mTableMerger;
+
+ struct FileToProcess {
+ Source source;
+ ResourceFile file;
+ };
+ std::map<ResourceName, FileToProcess> mFilesToProcess;
};
int link(const std::vector<StringPiece>& args) {
@@ -755,6 +810,9 @@
.requiredFlag("--manifest", "Path to the Android manifest to build",
&options.manifestPath)
.optionalFlagList("-I", "Adds an Android APK to link against", &options.includePaths)
+ .optionalFlagList("-R", "Compilation unit to link, using `overlay` semantics. "
+ "The last conflicting resource given takes precedence.",
+ &options.overlayFiles)
.optionalFlag("--java", "Directory in which to generate R.java",
&options.generateJavaClassPath)
.optionalFlag("--proguard", "Output file for generated Proguard rules",
@@ -794,7 +852,7 @@
options.targetSdkVersionDefault = util::utf8ToUtf16(targetSdkVersion.value());
}
- LinkCommand cmd = { options };
+ LinkCommand cmd(options);
return cmd.run(flags.getArgs());
}
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index 1eea410..a06a1bf 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -37,7 +37,7 @@
/**
* This will merge packages with the same package name (or no package name).
*/
-bool TableMerger::merge(const Source& src, ResourceTable* table) {
+bool TableMerger::merge(const Source& src, ResourceTable* table, bool overrideExisting) {
const uint8_t desiredPackageId = mContext->getPackageId();
bool error = false;
@@ -55,7 +55,7 @@
// mangled, then looked up at resolution time.
// Also, when linking, we convert references with no package name to use
// the compilation package name.
- if (!doMerge(src, table, package.get(), false)) {
+ if (!doMerge(src, table, package.get(), false, overrideExisting)) {
error = true;
}
}
@@ -79,7 +79,7 @@
bool mangle = packageName != mContext->getCompilationPackage();
mMergedPackages.insert(package->name);
- if (!doMerge(src, table, package.get(), mangle)) {
+ if (!doMerge(src, table, package.get(), mangle, false)) {
error = true;
}
}
@@ -87,7 +87,8 @@
}
bool TableMerger::doMerge(const Source& src, ResourceTable* srcTable,
- ResourceTablePackage* srcPackage, const bool manglePackage) {
+ ResourceTablePackage* srcPackage, const bool manglePackage,
+ const bool overrideExisting) {
bool error = false;
for (auto& srcType : srcPackage->types) {
@@ -149,7 +150,7 @@
if (iter != dstEntry->values.end() && iter->config == srcValue.config) {
const int collisionResult = ResourceTable::resolveValueCollision(
iter->value.get(), srcValue.value.get());
- if (collisionResult == 0) {
+ if (collisionResult == 0 && !overrideExisting) {
// Error!
ResourceNameRef resourceName(srcPackage->name,
srcType->type,
diff --git a/tools/aapt2/link/TableMerger.h b/tools/aapt2/link/TableMerger.h
index c903f1b..a2c9dbf 100644
--- a/tools/aapt2/link/TableMerger.h
+++ b/tools/aapt2/link/TableMerger.h
@@ -63,7 +63,7 @@
/**
* Merges resources from the same or empty package. This is for local sources.
*/
- bool merge(const Source& src, ResourceTable* table);
+ bool merge(const Source& src, ResourceTable* table, bool overrideExisting);
/**
* Merges resources from the given package, mangling the name. This is for static libraries.
@@ -79,7 +79,7 @@
std::queue<FileToMerge> mFilesToMerge;
bool doMerge(const Source& src, ResourceTable* srcTable, ResourceTablePackage* srcPackage,
- const bool manglePackage);
+ const bool manglePackage, const bool overrideExisting);
std::unique_ptr<Value> cloneAndMangle(ResourceTable* table, const std::u16string& package,
Value* value);
diff --git a/tools/aapt2/link/TableMerger_test.cpp b/tools/aapt2/link/TableMerger_test.cpp
index 0af4314..b7ffba7 100644
--- a/tools/aapt2/link/TableMerger_test.cpp
+++ b/tools/aapt2/link/TableMerger_test.cpp
@@ -59,7 +59,7 @@
ResourceTable finalTable;
TableMerger merger(mContext.get(), &finalTable);
- ASSERT_TRUE(merger.merge({}, tableA.get()));
+ ASSERT_TRUE(merger.merge({}, tableA.get(), false));
ASSERT_TRUE(merger.mergeAndMangle({}, u"com.app.b", tableB.get()));
EXPECT_TRUE(merger.getMergedPackages().count(u"com.app.b") != 0);
@@ -89,7 +89,7 @@
ResourceTable finalTable;
TableMerger merger(mContext.get(), &finalTable);
- ASSERT_TRUE(merger.merge({}, tableA.get()));
+ ASSERT_TRUE(merger.merge({}, tableA.get(), false));
ASSERT_TRUE(merger.mergeAndMangle({}, u"com.app.b", tableB.get()));
FileReference* f = test::getValue<FileReference>(&finalTable, u"@com.app.a:xml/file");