Merge "Fix test by finding default physical port" into rvc-dev
diff --git a/car-lib/src/android/car/hardware/property/CarPropertyManager.java b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
index 9065b9a..dafa8bc 100644
--- a/car-lib/src/android/car/hardware/property/CarPropertyManager.java
+++ b/car-lib/src/android/car/hardware/property/CarPropertyManager.java
@@ -694,11 +694,11 @@
         void onPropertyChanged(final CarPropertyEvent event) {
             // throw away old sensor data as oneway binder call can change order.
             long updateTime = event.getCarPropertyValue().getTimestamp();
-            if (updateTime < mLastUpdateTime) {
+            int areaId = event.getCarPropertyValue().getAreaId();
+            if (!needUpdateForAreaId(areaId, updateTime)) {
                 Log.w(TAG, "dropping old property data");
                 return;
             }
-            mLastUpdateTime = updateTime;
             List<CarPropertyEventCallback> listeners;
             synchronized (mActivePropertyListener) {
                 listeners = new ArrayList<>(getListeners());
@@ -706,7 +706,7 @@
             listeners.forEach(new Consumer<CarPropertyEventCallback>() {
                 @Override
                 public void accept(CarPropertyEventCallback listener) {
-                    if (needUpdate(listener, updateTime)) {
+                    if (needUpdateForSelectedListener(listener, updateTime)) {
                         listener.onChangeEvent(event.getCarPropertyValue());
                     }
                 }
diff --git a/car-lib/src/com/android/car/internal/CarRatedFloatListeners.java b/car-lib/src/com/android/car/internal/CarRatedFloatListeners.java
index 93519d6..566eed7 100644
--- a/car-lib/src/com/android/car/internal/CarRatedFloatListeners.java
+++ b/car-lib/src/com/android/car/internal/CarRatedFloatListeners.java
@@ -16,6 +16,8 @@
 
 package com.android.car.internal;
 
+import android.util.SparseArray;
+
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -36,7 +38,8 @@
 
     private float mUpdateRate;
 
-    protected long mLastUpdateTime = -1;
+    // key: areaId, value: lastUpdateTime in nanosecond
+    protected SparseArray<Long> mAreaIdToLastUpdateTime = new SparseArray<>();
 
     protected CarRatedFloatListeners(float rate) {
         mUpdateRate = rate;
@@ -105,7 +108,7 @@
      * @param eventTimeStamp
      * @return true if listener need to be notified.
      */
-    public boolean needUpdate(T listener, long eventTimeStamp) {
+    public boolean needUpdateForSelectedListener(T listener, long eventTimeStamp) {
         Long nextUpdateTime = mListenersUpdateTime.get(listener);
         Float updateRate = mListenersToRate.get(listener);
         /** Update ON_CHANGE property. */
@@ -121,6 +124,21 @@
         return false;
     }
 
+    /**
+     * @param areaId AreaId in CarPropertyValue
+     * @param eventTime TimeStamp in CarPropertyValue
+     * @return true if eventTime is greater than the last event time for the same areaId.
+     */
+    public boolean needUpdateForAreaId(int areaId, long eventTime) {
+        long lastUpdateTime = mAreaIdToLastUpdateTime.get(areaId, 0L);
+        if (eventTime >= lastUpdateTime) {
+            mAreaIdToLastUpdateTime.put(areaId, eventTime);
+            return true;
+        }
+        return false;
+    }
+
+
     public Collection<T> getListeners() {
         return mListenersToRate.keySet();
     }
diff --git a/service/src/com/android/car/am/FixedActivityService.java b/service/src/com/android/car/am/FixedActivityService.java
index d3e3c6f..abb1eca 100644
--- a/service/src/com/android/car/am/FixedActivityService.java
+++ b/service/src/com/android/car/am/FixedActivityService.java
@@ -28,6 +28,7 @@
 import android.app.ActivityOptions;
 import android.app.IActivityManager;
 import android.app.IProcessObserver;
+import android.app.Presentation;
 import android.app.TaskStackListener;
 import android.car.hardware.power.CarPowerManager;
 import android.content.BroadcastReceiver;
@@ -38,6 +39,7 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.hardware.display.DisplayManager;
 import android.net.Uri;
 import android.os.HandlerThread;
 import android.os.RemoteException;
@@ -50,6 +52,8 @@
 
 import com.android.car.CarLocalServices;
 import com.android.car.CarServiceBase;
+import com.android.car.CarServiceUtils;
+import com.android.car.R;
 import com.android.car.user.CarUserService;
 import com.android.internal.annotations.GuardedBy;
 
@@ -122,6 +126,8 @@
 
     private final IActivityManager mAm;
 
+    private final DisplayManager mDm;
+
     private final UserManager mUm;
 
     private final CarUserService.UserCallback mUserCallback = new CarUserService.UserCallback() {
@@ -240,6 +246,9 @@
             new SparseArray<>(/* capacity= */ 1); // default to one cluster only case
 
     @GuardedBy("mLock")
+    private final SparseArray<Presentation> mBlockingPresentations = new SparseArray<>(1);
+
+    @GuardedBy("mLock")
     private boolean mEventMonitoringActive;
 
     @GuardedBy("mLock")
@@ -262,6 +271,7 @@
         mContext = context;
         mAm = ActivityManager.getService();
         mUm = context.getSystemService(UserManager.class);
+        mDm = context.getSystemService(DisplayManager.class);
         mHandlerThread.start();
     }
 
@@ -377,8 +387,38 @@
                 }
                 return false;
             }
-            for (int i = 0; i < mRunningActivities.size(); i++) {
-                mRunningActivities.valueAt(i).isVisible = false;
+            for (int i = mRunningActivities.size() - 1; i >= 0; i--) {
+                RunningActivityInfo activityInfo = mRunningActivities.valueAt(i);
+                activityInfo.isVisible = false;
+                if (isUserAllowedToLaunchActivity(activityInfo.userId)) {
+                    continue;
+                }
+                final int displayIdForActivity = mRunningActivities.keyAt(i);
+                if (activityInfo.taskId != INVALID_TASK_ID) {
+                    Log.i(TAG_AM, "Finishing fixed activity on user switching:"
+                            + activityInfo);
+                    try {
+                        mAm.removeTask(activityInfo.taskId);
+                    } catch (RemoteException e) {
+                        Log.e(TAG_AM, "remote exception from AM", e);
+                    }
+                    CarServiceUtils.runOnMain(() -> {
+                        Display display = mDm.getDisplay(displayIdForActivity);
+                        if (display == null) {
+                            Log.e(TAG_AM, "Display not available, cannot launnch window:"
+                                    + displayIdForActivity);
+                            return;
+                        }
+                        Presentation p = new Presentation(mContext, display,
+                                android.R.style.Theme_Black_NoTitleBar_Fullscreen);
+                        p.setContentView(R.layout.activity_continuous_blank);
+                        p.show();
+                        synchronized (mLock) {
+                            mBlockingPresentations.append(displayIdForActivity, p);
+                        }
+                    });
+                }
+                mRunningActivities.removeAt(i);
             }
             for (StackInfo stackInfo : infos) {
                 RunningActivityInfo activityInfo = mRunningActivities.get(stackInfo.displayId);
@@ -407,6 +447,7 @@
                     activityInfo.taskId = INVALID_TASK_ID;
                 }
             }
+
             for (int i = 0; i < mRunningActivities.size(); i++) {
                 RunningActivityInfo activityInfo = mRunningActivities.valueAt(i);
                 long timeSinceLastLaunchMs = now - activityInfo.lastLaunchTimeMs;
@@ -417,7 +458,6 @@
                     continue;
                 }
                 if (!isComponentAvailable(activityInfo.intent.getComponent(),
-                        activityInfo.userId) || !isUserAllowedToLaunchActivity(
                         activityInfo.userId)) {
                     continue;
                 }
@@ -556,6 +596,10 @@
         }
         boolean startMonitoringEvents = false;
         synchronized (mLock) {
+            Presentation p = mBlockingPresentations.removeReturnOld(displayId);
+            if (p != null) {
+                p.dismiss();
+            }
             if (mRunningActivities.size() == 0) {
                 startMonitoringEvents = true;
             }