Merge "Freeze {ipmemorystore,networkstack}-aidl-interfaces as version 2." into qt-dev
diff --git a/api/current.txt b/api/current.txt
index b0452e3..81069c5 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5502,8 +5502,6 @@
     method @DimenRes public int getDesiredHeightResId();
     method @NonNull public android.graphics.drawable.Icon getIcon();
     method @NonNull public android.app.PendingIntent getIntent();
-    method @Deprecated public boolean getSuppressInitialNotification();
-    method @Deprecated public boolean getSuppressNotification();
     method public boolean isNotificationSuppressed();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.Notification.BubbleMetadata> CREATOR;
@@ -5518,7 +5516,6 @@
     method @NonNull public android.app.Notification.BubbleMetadata.Builder setDesiredHeightResId(@DimenRes int);
     method @NonNull public android.app.Notification.BubbleMetadata.Builder setIcon(@NonNull android.graphics.drawable.Icon);
     method @NonNull public android.app.Notification.BubbleMetadata.Builder setIntent(@NonNull android.app.PendingIntent);
-    method @Deprecated @NonNull public android.app.Notification.BubbleMetadata.Builder setSuppressInitialNotification(boolean);
     method @NonNull public android.app.Notification.BubbleMetadata.Builder setSuppressNotification(boolean);
   }
 
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index d0361b7..15b571f 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -8642,27 +8642,6 @@
         }
 
         /**
-         * @return whether this bubble should suppress the initial notification when it is posted.
-         *
-         * @see BubbleMetadata.Builder#setSuppressInitialNotification(boolean)
-         * @deprecated TO BE REMOVED, use {@link #isNotificationSuppressed()} instead.
-         */
-        @Deprecated
-        public boolean getSuppressInitialNotification() {
-            return isNotificationSuppressed();
-        }
-
-        /**
-         * @return whether this bubble should suppress the notification when it is posted.
-         *
-         * @see BubbleMetadata.Builder#setSuppressNotification(boolean)
-         * @deprecated TO BE REMOVED, use {@link #isNotificationSuppressed()} instead.
-         */
-        public boolean getSuppressNotification() {
-            return isNotificationSuppressed();
-        }
-
-        /**
          * @return whether this bubble should suppress the notification when it is posted.
          *
          * @see BubbleMetadata.Builder#setSuppressNotification(boolean)
@@ -8818,27 +8797,6 @@
             }
 
             /**
-             * If set and the app creating the bubble is in the foreground, the bubble will be
-             * posted <b>without</b> the associated notification in the notification shade.
-             * Subsequent update notifications to this bubble will post a notification in the shade.
-             *
-             * <p>If the app creating the bubble is not in the foreground this flag has no effect.
-             * </p>
-             *
-             * <p>Generally this flag should only be set if the user has performed an action to
-             * request or create a bubble.</p>
-             *
-             * @deprecated TO BE REMOVED, use {@link #setSuppressNotification(boolean)} instead.
-             */
-            @Deprecated
-            @NonNull
-            public BubbleMetadata.Builder setSuppressInitialNotification(
-                    boolean shouldSupressNotif) {
-                setFlag(FLAG_SUPPRESS_NOTIFICATION, shouldSupressNotif);
-                return this;
-            }
-
-            /**
              * If set and the app posting the bubble is in the foreground, the bubble will be
              * posted <b>without</b> the associated notification in the notification shade.
              *
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 21a8f4c..ad3203e 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2542,9 +2542,10 @@
          mirror the content of the default display. -->
     <bool name="config_localDisplaysMirrorContent">true</bool>
 
-    <!-- Indicates whether local non-default displays are private.
-         {@see android.view.Display#FLAG_PRIVATE} -->
-    <bool name="config_localDisplaysPrivate">false</bool>
+    <!-- Controls if local secondary displays should be private or not. Value specified in the array
+         represents physical port address of each display and display in this list will be marked
+         as private. {@see android.view.Display#FLAG_PRIVATE} -->
+    <integer-array translatable="false" name="config_localPrivateDisplayPorts"></integer-array>
 
     <!-- The default mode for the default display. One of the following values (See Display.java):
              0 - COLOR_MODE_DEFAULT
@@ -3862,6 +3863,10 @@
          {@see android.view.Display#FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS} -->
     <string name="config_secondaryHomeComponent" translatable="false">com.android.launcher3/com.android.launcher3.SecondaryDisplayLauncher</string>
 
+    <!-- Force secondary home launcher specified in config_secondaryHomeComponent always. If this is
+         not set, secondary home launcher can be replaced by user. -->
+    <bool name ="config_useSystemProvidedLauncherForSecondary">false</bool>
+
     <!-- If device supports corner radius on windows.
          This should be turned off on low-end devices to improve animation performance. -->
     <bool name="config_supportsRoundedCornersOnWindows">true</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 7cf03fea..085ce56 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -394,7 +394,7 @@
   <java-symbol type="bool" name="config_supportsInsecureLockScreen" />
   <java-symbol type="bool" name="config_guestUserEphemeral" />
   <java-symbol type="bool" name="config_localDisplaysMirrorContent" />
-  <java-symbol type="bool" name="config_localDisplaysPrivate" />
+  <java-symbol type="array" name="config_localPrivateDisplayPorts" />
   <java-symbol type="integer" name="config_defaultDisplayDefaultColorMode" />
   <java-symbol type="bool" name="config_enableAppWidgetService" />
   <java-symbol type="string" name="config_defaultPictureInPictureScreenEdgeInsets" />
@@ -3678,6 +3678,7 @@
 
   <!-- For Secondary Launcher -->
   <java-symbol type="string" name="config_secondaryHomeComponent" />
+  <java-symbol type="bool" name="config_useSystemProvidedLauncherForSecondary" />
 
   <java-symbol type="string" name="battery_saver_notification_channel_name" />
   <java-symbol type="string" name="battery_saver_sticky_disabled_notification_title" />
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 5e5ef26..85fbdf6 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -405,7 +405,9 @@
                 mInfo.presentationDeadlineNanos = phys.presentationDeadlineNanos;
                 mInfo.state = mState;
                 mInfo.uniqueId = getUniqueId();
-                mInfo.address = DisplayAddress.fromPhysicalDisplayId(mPhysicalDisplayId);
+                final DisplayAddress.Physical physicalAddress =
+                        DisplayAddress.fromPhysicalDisplayId(mPhysicalDisplayId);
+                mInfo.address = physicalAddress;
 
                 // Assume that all built-in displays that have secure output (eg. HDCP) also
                 // support compositing from gralloc protected buffers.
@@ -462,7 +464,7 @@
                         mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY;
                     }
 
-                    if (res.getBoolean(com.android.internal.R.bool.config_localDisplaysPrivate)) {
+                    if (isDisplayPrivate(physicalAddress)) {
                         mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE;
                     }
                 }
@@ -797,6 +799,24 @@
             }
             return modes;
         }
+
+        private boolean isDisplayPrivate(DisplayAddress.Physical physicalAddress) {
+            if (physicalAddress == null) {
+                return false;
+            }
+            final Resources res = getOverlayContext().getResources();
+            int[] ports = res.getIntArray(
+                    com.android.internal.R.array.config_localPrivateDisplayPorts);
+            if (ports != null) {
+                int port = physicalAddress.getPort();
+                for (int p : ports) {
+                    if (p == port) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
     }
 
     /** Supplies a context whose Resources apply runtime-overlays */
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 7bc9600..a55ee5f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -5810,8 +5810,10 @@
      */
     Intent getSecondaryHomeIntent(String preferredPackage) {
         final Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
-        if (preferredPackage == null) {
-            // Using the component stored in config if no package name.
+        final boolean useSystemProvidedLauncher = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_useSystemProvidedLauncherForSecondary);
+        if (preferredPackage == null || useSystemProvidedLauncher) {
+            // Using the component stored in config if no package name or forced.
             final String secondaryHomeComponent = mContext.getResources().getString(
                     com.android.internal.R.string.config_secondaryHomeComponent);
             intent.setComponent(ComponentName.unflattenFromString(secondaryHomeComponent));
diff --git a/services/net/Android.bp b/services/net/Android.bp
index 11e426c..a44d835 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -33,6 +33,7 @@
         "java/android/net/INetworkStackConnector.aidl",
         "java/android/net/INetworkStackStatusCallback.aidl",
         "java/android/net/InitialConfigurationParcelable.aidl",
+        "java/android/net/NattKeepalivePacketDataParcelable.aidl",
         "java/android/net/PrivateDnsConfigParcel.aidl",
         "java/android/net/ProvisioningConfigurationParcelable.aidl",
         "java/android/net/TcpKeepalivePacketDataParcelable.aidl",
diff --git a/core/java/android/net/NattKeepalivePacketData.java b/services/net/java/android/net/NattKeepalivePacketData.java
similarity index 84%
rename from core/java/android/net/NattKeepalivePacketData.java
rename to services/net/java/android/net/NattKeepalivePacketData.java
index 5c55a98b..06838fe 100644
--- a/core/java/android/net/NattKeepalivePacketData.java
+++ b/services/net/java/android/net/NattKeepalivePacketData.java
@@ -19,8 +19,10 @@
 import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS;
 import static android.net.SocketKeepalive.ERROR_INVALID_PORT;
 
+import android.annotation.NonNull;
 import android.net.SocketKeepalive.InvalidPacketException;
 import android.net.util.IpUtils;
+import android.os.Parcelable;
 import android.system.OsConstants;
 
 import java.net.Inet4Address;
@@ -29,8 +31,7 @@
 import java.nio.ByteOrder;
 
 /** @hide */
-public final class NattKeepalivePacketData extends KeepalivePacketData {
-
+public final class NattKeepalivePacketData extends KeepalivePacketData implements Parcelable {
     // This should only be constructed via static factory methods, such as
     // nattKeepalivePacket
     private NattKeepalivePacketData(InetAddress srcAddress, int srcPort,
@@ -77,4 +78,18 @@
 
         return new NattKeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, buf.array());
     }
+
+     /**
+     * Convert this NattKeepalivePacketData to a NattKeepalivePacketDataParcelable.
+     */
+    @NonNull
+    public NattKeepalivePacketDataParcelable toStableParcelable() {
+        final NattKeepalivePacketDataParcelable parcel = new NattKeepalivePacketDataParcelable();
+
+        parcel.srcAddress = srcAddress.getAddress();
+        parcel.srcPort = srcPort;
+        parcel.dstAddress = dstAddress.getAddress();
+        parcel.dstPort = dstPort;
+        return parcel;
+    }
 }
diff --git a/services/net/java/android/net/NattKeepalivePacketDataParcelable.aidl b/services/net/java/android/net/NattKeepalivePacketDataParcelable.aidl
new file mode 100644
index 0000000..6f006d4
--- /dev/null
+++ b/services/net/java/android/net/NattKeepalivePacketDataParcelable.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+parcelable NattKeepalivePacketDataParcelable {
+    byte[] srcAddress;
+    int srcPort;
+    byte[] dstAddress;
+    int dstPort;
+}
+
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
new file mode 100644
index 0000000..9e255fe
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.view.DisplayAddress;
+import android.view.SurfaceControl;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.dx.mockito.inline.extended.StaticMockitoSession;
+import com.android.server.LocalServices;
+import com.android.server.lights.LightsManager;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.quality.Strictness;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LocalDisplayAdapterTest {
+    private static final long HANDLER_WAIT_MS = 100;
+
+    private static final int PHYSICAL_DISPLAY_ID_MODEL_SHIFT = 8;
+
+    private StaticMockitoSession mMockitoSession;
+
+    private LocalDisplayAdapter mAdapter;
+
+    @Mock
+    private DisplayManagerService.SyncRoot mMockedSyncRoot;
+    @Mock
+    private Context mMockedContext;
+    @Mock
+    private Resources mMockedResources;
+    @Mock
+    private LightsManager mMockedLightsManager;
+
+    private Handler mHandler;
+
+    private TestListener mListener = new TestListener();
+
+    private LinkedList<Long> mDisplayIds = new LinkedList<>();
+
+    @Before
+    public void setUp() throws Exception {
+        mMockitoSession = mockitoSession()
+                .initMocks(this)
+                .mockStatic(SurfaceControl.class)
+                .strictness(Strictness.LENIENT)
+                .startMocking();
+        mHandler = new Handler(Looper.getMainLooper());
+        doReturn(mMockedResources).when(mMockedContext).getResources();
+        LocalServices.removeServiceForTest(LightsManager.class);
+        LocalServices.addService(LightsManager.class, mMockedLightsManager);
+        mAdapter = new LocalDisplayAdapter(mMockedSyncRoot, mMockedContext, mHandler,
+                mListener);
+        spyOn(mAdapter);
+        doReturn(mMockedContext).when(mAdapter).getOverlayContext();
+    }
+
+    @After
+    public void tearDown() {
+        if (mMockitoSession != null) {
+            mMockitoSession.finishMocking();
+        }
+    }
+
+    /**
+     * Confirm that display is marked as private when it is listed in
+     * com.android.internal.R.array.config_localPrivateDisplayPorts.
+     */
+    @Test
+    public void testPrivateDisplay() throws Exception {
+        // needs default one always
+        final long displayId0 = 0;
+        setUpDisplay(new DisplayConfig(displayId0, createDummyDisplayInfo()));
+        final long displayId1 = 1;
+        setUpDisplay(new DisplayConfig(displayId1, createDummyDisplayInfo()));
+        final long displayId2 = 2;
+        setUpDisplay(new DisplayConfig(displayId2, createDummyDisplayInfo()));
+        updateAvailableDisplays();
+        // display 1 should be marked as private while display 2 is not.
+        doReturn(new int[]{(int) displayId1}).when(mMockedResources)
+                .getIntArray(com.android.internal.R.array.config_localPrivateDisplayPorts);
+        mAdapter.registerLocked();
+
+        waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+
+        // This should be public
+        assertDisplay(mListener.addedDisplays.get(0).getDisplayDeviceInfoLocked(), displayId0,
+                false);
+        // This should be private
+        assertDisplay(mListener.addedDisplays.get(1).getDisplayDeviceInfoLocked(), displayId1,
+                true);
+        // This should be public
+        assertDisplay(mListener.addedDisplays.get(2).getDisplayDeviceInfoLocked(), displayId2,
+                false);
+    }
+
+    /**
+     * Confirm that all local displays are public when config_localPrivateDisplayPorts is empty.
+     */
+    @Test
+    public void testPublicDisplaysForNoConfigLocalPrivateDisplayPorts() throws Exception {
+        // needs default one always
+        final long displayId0 = 0;
+        setUpDisplay(new DisplayConfig(displayId0, createDummyDisplayInfo()));
+        final long displayId1 = 1;
+        setUpDisplay(new DisplayConfig(displayId1, createDummyDisplayInfo()));
+        updateAvailableDisplays();
+        // config_localPrivateDisplayPorts is null
+        mAdapter.registerLocked();
+
+        waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+
+        // This should be public
+        assertDisplay(mListener.addedDisplays.get(0).getDisplayDeviceInfoLocked(), displayId0,
+                false);
+        // This should be public
+        assertDisplay(mListener.addedDisplays.get(1).getDisplayDeviceInfoLocked(), displayId1,
+                false);
+    }
+
+    private void assertDisplay(DisplayDeviceInfo info, long expectedPort, boolean shouldBePrivate) {
+        DisplayAddress.Physical physical = (DisplayAddress.Physical) info.address;
+        assertNotNull(physical);
+        assertEquals(expectedPort, physical.getPort());
+        assertEquals(shouldBePrivate, (info.flags & DisplayDeviceInfo.FLAG_PRIVATE) != 0);
+    }
+
+    private class DisplayConfig {
+        public final long displayId;
+        public final IBinder displayToken = new Binder();
+        public final SurfaceControl.PhysicalDisplayInfo displayInfo;
+
+        private DisplayConfig(long displayId, SurfaceControl.PhysicalDisplayInfo displayInfo) {
+            this.displayId = displayId | (0x1 << PHYSICAL_DISPLAY_ID_MODEL_SHIFT);
+            this.displayInfo = displayInfo;
+        }
+    }
+
+    private void setUpDisplay(DisplayConfig config) {
+        mDisplayIds.add(config.displayId);
+        doReturn(config.displayToken).when(
+                () -> SurfaceControl.getPhysicalDisplayToken(config.displayId));
+        doReturn(new SurfaceControl.PhysicalDisplayInfo[]{
+                config.displayInfo
+        }).when(() -> SurfaceControl.getDisplayConfigs(config.displayToken));
+        doReturn(0).when(() -> SurfaceControl.getActiveConfig(config.displayToken));
+        doReturn(0).when(() -> SurfaceControl.getActiveColorMode(config.displayToken));
+        doReturn(new int[]{
+                0
+        }).when(() -> SurfaceControl.getDisplayColorModes(config.displayToken));
+        doReturn(new int[]{
+                0
+        }).when(() -> SurfaceControl.getAllowedDisplayConfigs(config.displayToken));
+    }
+
+    private void updateAvailableDisplays() {
+        long[] ids = new long[mDisplayIds.size()];
+        int i = 0;
+        for (long id : mDisplayIds) {
+            ids[i] = id;
+            i++;
+        }
+        doReturn(ids).when(() -> SurfaceControl.getPhysicalDisplayIds());
+    }
+
+    private SurfaceControl.PhysicalDisplayInfo createDummyDisplayInfo() {
+        SurfaceControl.PhysicalDisplayInfo info = new SurfaceControl.PhysicalDisplayInfo();
+        info.density = 100;
+        info.xDpi = 100;
+        info.yDpi = 100;
+        info.secure = false;
+        info.width = 800;
+        info.height = 600;
+
+        return info;
+    }
+
+    private void waitForHandlerToComplete(Handler handler, long waitTimeMs)
+            throws InterruptedException {
+        final Object lock = new Object();
+        synchronized (lock) {
+            handler.post(() -> {
+                synchronized (lock) {
+                    lock.notify();
+                }
+            });
+            lock.wait(waitTimeMs);
+        }
+    }
+
+    private class TestListener implements DisplayAdapter.Listener {
+        public ArrayList<DisplayDevice> addedDisplays = new ArrayList<>();
+
+        @Override
+        public void onDisplayDeviceEvent(DisplayDevice device, int event) {
+            if (event == DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED) {
+                addedDisplays.add(device);
+            }
+        }
+
+        @Override
+        public void onTraversalRequested() {
+
+        }
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index bac1ecd..6d27e6d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -31,6 +31,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.server.wm.ActivityDisplay.POSITION_TOP;
@@ -55,6 +56,7 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.util.Pair;
@@ -537,6 +539,71 @@
     }
 
     /**
+     * Tests that the default secondary home activity is always picked when it is in forced by
+     * config_useSystemProvidedLauncherForSecondary.
+     */
+    @Test
+    public void testResolveSecondaryHomeActivityForced() {
+        Resources resources = mContext.getResources();
+        spyOn(resources);
+        final String defaultSecondaryHome =
+                "com.android.test/com.android.test.TestDefaultSecondaryHome";
+        final ComponentName secondaryComp = ComponentName.unflattenFromString(defaultSecondaryHome);
+        doReturn(defaultSecondaryHome).when(resources).getString(
+                com.android.internal.R.string.config_secondaryHomeComponent);
+        doReturn(true).when(resources).getBoolean(
+                com.android.internal.R.bool.config_useSystemProvidedLauncherForSecondary);
+
+        final Intent secondaryHomeIntent = mService.getSecondaryHomeIntent(null);
+        assertEquals(secondaryComp, secondaryHomeIntent.getComponent());
+
+        final ActivityInfo aInfoSecondary = new ActivityInfo();
+        aInfoSecondary.name = secondaryComp.getClassName();
+        aInfoSecondary.applicationInfo = new ApplicationInfo();
+        aInfoSecondary.applicationInfo.packageName = secondaryComp.getPackageName();
+        doReturn(aInfoSecondary).when(mRootActivityContainer).resolveHomeActivity(anyInt(),
+                refEq(secondaryHomeIntent));
+
+        final Intent homeIntent = mService.getHomeIntent();
+        final ActivityInfo aInfoDefault = new ActivityInfo();
+        aInfoDefault.name = "fakeHomeActivity";
+        aInfoDefault.applicationInfo = new ApplicationInfo();
+        aInfoDefault.applicationInfo.packageName = "fakeHomePackage";
+        doReturn(aInfoDefault).when(mRootActivityContainer).resolveHomeActivity(anyInt(),
+                refEq(homeIntent));
+
+        // Let resolveActivities call to validate both main launcher and second launcher so that
+        // resolveActivities call does not work as enabler for secondary.
+        final List<ResolveInfo> resolutions1 = new ArrayList<>();
+        final ResolveInfo resolveInfo1 = new ResolveInfo();
+        resolveInfo1.activityInfo = new ActivityInfo();
+        resolveInfo1.activityInfo.name = aInfoDefault.name;
+        resolveInfo1.activityInfo.applicationInfo = aInfoDefault.applicationInfo;
+        resolutions1.add(resolveInfo1);
+        doReturn(resolutions1).when(mRootActivityContainer).resolveActivities(anyInt(),
+                refEq(homeIntent));
+        final List<ResolveInfo> resolutions2 = new ArrayList<>();
+        final ResolveInfo resolveInfo2 = new ResolveInfo();
+        resolveInfo2.activityInfo = new ActivityInfo();
+        resolveInfo2.activityInfo.name = aInfoSecondary.name;
+        resolveInfo2.activityInfo.applicationInfo = aInfoSecondary.applicationInfo;
+        resolutions2.add(resolveInfo2);
+        doReturn(resolutions2).when(mRootActivityContainer).resolveActivities(anyInt(),
+                refEq(secondaryHomeIntent));
+
+        doReturn(true).when(mRootActivityContainer).canStartHomeOnDisplay(
+                any(), anyInt(), anyBoolean());
+
+        final Pair<ActivityInfo, Intent> resolvedInfo = mRootActivityContainer
+                .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */);
+
+        assertEquals(secondaryComp.getClassName(), resolvedInfo.first.name);
+        assertEquals(secondaryComp.getPackageName(),
+                resolvedInfo.first.applicationInfo.packageName);
+        assertEquals(aInfoSecondary.name, resolvedInfo.first.name);
+    }
+
+    /**
      * Tests that secondary home should be selected if default home not support secondary displays
      * or there is no matched activity in the same package as selected default home.
      */
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index c291b39..45cea81 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -693,7 +693,7 @@
 
   // If the resource type was not recognized, write the error and return false.
   diag_->Error(DiagMessage(out_resource->source)
-              << "unknown resource type '" << parser->element_name() << "'");
+              << "unknown resource type '" << resource_type << "'");
   return false;
 }