resolve merge conflicts of adc8483604c691dd081433e0e86f0f0da78d31dd to qt-qpr1-dev-plus-aosp

Bug: None
Test: I solemnly swear I tested this conflict resolution.
Change-Id: Ie90d0b9d919c7702816338810a8d31fa821b4e59
diff --git a/res/values/config.xml b/res/values/config.xml
index 89998f3..d06dff2 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -19,4 +19,5 @@
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!--  Activity to present for free navigation -->
     <string name="freeNavigationIntent" translatable="false">intent:#Intent;component=android.car.cluster/.FakeFreeNavigationActivity;launchFlags=0x24000000;end</string>
+    <bool name="navigationOnly">false</bool>
 </resources>
diff --git a/src/android/car/cluster/ClusterRenderingService.java b/src/android/car/cluster/ClusterRenderingService.java
index f27b036..87e7592 100644
--- a/src/android/car/cluster/ClusterRenderingService.java
+++ b/src/android/car/cluster/ClusterRenderingService.java
@@ -16,20 +16,25 @@
 package android.car.cluster;
 
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.view.Display.INVALID_DISPLAY;
 
 import static java.lang.Integer.parseInt;
 
+import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.car.CarNotConnectedException;
 import android.car.cluster.navigation.NavigationState.NavigationStateProto;
 import android.car.cluster.renderer.InstrumentClusterRenderingService;
 import android.car.cluster.renderer.NavigationRenderer;
 import android.car.navigation.CarNavigationInstrumentCluster;
+import android.content.ComponentName;
 import android.content.Intent;
 import android.graphics.Rect;
+import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManager.DisplayListener;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.IBinder;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -56,8 +61,7 @@
 public class ClusterRenderingService extends InstrumentClusterRenderingService implements
         ImageResolver.BitmapFetcher {
     private static final String TAG = "Cluster.Service";
-
-    private static final int NO_DISPLAY = -1;
+    private static final int NAVIGATION_ACTIVITY_RETRY_INTERVAL_MS = 1000;
 
     static final int NAV_STATE_EVENT_ID = 1;
     static final String LOCAL_BINDING_ACTION = "local";
@@ -65,9 +69,15 @@
 
     private List<ServiceClient> mClients = new ArrayList<>();
     private ClusterDisplayProvider mDisplayProvider;
-    private int mDisplayId = NO_DISPLAY;
+
+    private int mClusterDisplayId = INVALID_DISPLAY;
+
+    private boolean mInstrumentClusterHelperReady;
+
     private final IBinder mLocalBinder = new LocalBinder();
     private final ImageResolver mImageResolver = new ImageResolver(this);
+    private final Handler mHandler = new Handler();
+    private final Runnable mLaunchMainActivity = this::launchMainActivity;
 
     public interface ServiceClient {
         void onKeyEvent(KeyEvent keyEvent);
@@ -82,11 +92,15 @@
     }
 
     private final DisplayListener mDisplayListener = new DisplayListener() {
+        // Called in the main thread, since ClusterDisplayProvider.DisplayListener was registered
+        // with null handler.
         @Override
         public void onDisplayAdded(int displayId) {
             Log.i(TAG, "Cluster display found, displayId: " + displayId);
-            mDisplayId = displayId;
-            launchMainActivity();
+            mClusterDisplayId = displayId;
+            if (mInstrumentClusterHelperReady) {
+                mHandler.post(mLaunchMainActivity);
+            }
         }
 
         @Override
@@ -102,7 +116,7 @@
 
     public void setActivityLaunchOptions(int displayId, ClusterActivityState state) {
         try {
-            ActivityOptions options = displayId != Display.INVALID_DISPLAY
+            ActivityOptions options = displayId != INVALID_DISPLAY
                     ? ActivityOptions.makeBasic().setLaunchDisplayId(displayId)
                     : null;
             setClusterActivityLaunchOptions(CarInstrumentClusterManager.CATEGORY_NAVIGATION,
@@ -136,9 +150,15 @@
     @Override
     public IBinder onBind(Intent intent) {
         Log.d(TAG, "onBind, intent: " + intent);
-        return LOCAL_BINDING_ACTION.equals(intent.getAction())
-                ? mLocalBinder
-                : super.onBind(intent);
+        if (LOCAL_BINDING_ACTION.equals(intent.getAction())) {
+            return mLocalBinder;
+        }
+        IBinder binder = super.onBind(intent);
+        mInstrumentClusterHelperReady = true;
+        if (mClusterDisplayId != INVALID_DISPLAY) {
+            mHandler.post(mLaunchMainActivity);
+        }
+        return binder;
     }
 
     @Override
@@ -149,12 +169,50 @@
     }
 
     private void launchMainActivity() {
+        mHandler.removeCallbacks(mLaunchMainActivity);
         ActivityOptions options = ActivityOptions.makeBasic();
-        options.setLaunchDisplayId(mDisplayId);
-        Intent intent = new Intent(this, MainClusterActivity.class);
-        intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
-        startActivityAsUser(intent, options.toBundle(), UserHandle.SYSTEM);
-        Log.i(TAG, String.format("launching main activity: %s (display: %d)", intent, mDisplayId));
+        options.setLaunchDisplayId(mClusterDisplayId);
+        boolean useNavigationOnly = getResources().getBoolean(R.bool.navigationOnly);
+        Intent intent;
+        int userId = UserHandle.USER_SYSTEM;
+        if (useNavigationOnly) {
+            intent = getNavigationActivityIntent(mClusterDisplayId);
+            if (intent == null) {
+                mHandler.postDelayed(mLaunchMainActivity, NAVIGATION_ACTIVITY_RETRY_INTERVAL_MS);
+                return;
+            }
+            userId = ActivityManager.getCurrentUser();
+            startFixedActivityModeForDisplayAndUser(intent, options, userId);
+        } else {
+            intent = getMainClusterActivityIntent();
+            startActivityAsUser(intent, options.toBundle(), UserHandle.SYSTEM);
+        }
+        Log.i(TAG, "launching main activity=" + intent + ", display=" + mClusterDisplayId
+                + ", userId=" + userId);
+    }
+
+    private Intent getMainClusterActivityIntent() {
+        return new Intent(this, MainClusterActivity.class).setFlags(FLAG_ACTIVITY_NEW_TASK);
+    }
+
+    private Intent getNavigationActivityIntent(int displayId) {
+        ComponentName component = MainClusterActivity.getNavigationActivity(this);
+        if (component == null) {
+            Log.e(TAG, "Failed to resolve the navigation activity");
+            return null;
+        }
+        Rect displaySize = new Rect(0, 0, 320, 240);  // Arbitrary size, better than nothing.
+        DisplayManager dm = (DisplayManager) getSystemService(DisplayManager.class);
+        Display display = dm.getDisplay(displayId);
+        if (display != null) {
+            display.getRectSize(displaySize);
+        }
+        return new Intent(Intent.ACTION_MAIN)
+            .setComponent(component)
+            .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+            .putExtra(CarInstrumentClusterManager.KEY_EXTRA_ACTIVITY_STATE,
+                ClusterActivityState.create(/* visible= */ true,
+                    /* unobscuredBounds= */ displaySize).toBundle());
     }
 
     @Override
diff --git a/src/android/car/cluster/MainClusterActivity.java b/src/android/car/cluster/MainClusterActivity.java
index e5f1311..b6a32f2 100644
--- a/src/android/car/cluster/MainClusterActivity.java
+++ b/src/android/car/cluster/MainClusterActivity.java
@@ -414,7 +414,7 @@
         }
         mHandler.removeCallbacks(mRetryLaunchNavigationActivity);
 
-        ComponentName navigationActivity = getNavigationActivity();
+        ComponentName navigationActivity = getNavigationActivity(this);
         mClusterViewModel.setFreeNavigationActivity(navigationActivity);
 
         try {
@@ -456,10 +456,10 @@
      * <li>Let the user select one from settings.
      * </ul>
      */
-    private ComponentName getNavigationActivity() {
-        PackageManager pm = getPackageManager();
+    static ComponentName getNavigationActivity(Context context) {
+        PackageManager pm = context.getPackageManager();
         int userId = ActivityManager.getCurrentUser();
-        String intentString = getString(R.string.freeNavigationIntent);
+        String intentString = context.getString(R.string.freeNavigationIntent);
 
         if (intentString == null) {
             Log.w(TAG, "No free navigation activity defined");