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;
}