Add driving safety region support with one time bypassing

- Driving safety regions of app tells which regional
  regulation the app supports.
- App still should have distractionOptimized metadata
  besides driving safety region metadata.
- Apps not supporting the curret system's region will be considered
  as not safe.
- driving safety region can be set from system properties:
  ro.android.car.drivingsafetyregion
- It can be also set through adb shell command for testing purpose but
  it is not allowed for user build.
  $ adb shell cmd car_service set-drivingsafety-region {REGION_NAME}
- Driving safety region is currently only for OEM apps only.
  Other than all region, there is no other standared regions
  defined.
- App should specify its regions using android.car.drivingsafetyregions
  metadata in AndroidManifest.
- Check added DrivingSafetyRegionTest for additional details on the
  expected behavior.

Bug: 193247516

Test: run added api test under userdebug or eng build
      $ atest android.car.apitest.DrivingSafetyRegionTest

Change-Id: I31728ac6cebf25ce93fac0e47a8dadee954e67e2
Merged-In: I31728ac6cebf25ce93fac0e47a8dadee954e67e2
diff --git a/car-lib/src/android/car/content/pm/CarPackageManager.java b/car-lib/src/android/car/content/pm/CarPackageManager.java
index e66d851..27eff37 100644
--- a/car-lib/src/android/car/content/pm/CarPackageManager.java
+++ b/car-lib/src/android/car/content/pm/CarPackageManager.java
@@ -16,20 +16,28 @@
 
 package android.car.content.pm;
 
+import static android.car.Car.PERMISSION_CONTROL_APP_BLOCKING;
+
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
+import android.annotation.UserIdInt;
 import android.app.PendingIntent;
 import android.car.Car;
 import android.car.CarManagerBase;
 import android.content.ComponentName;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
+import android.os.ServiceSpecificException;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * Provides car specific API related with package management.
@@ -77,6 +85,36 @@
     @Deprecated
     public static final int FLAG_SET_POLICY_REMOVE = 0x4;
 
+    /**
+     * Represents support of all regions for driving safety.
+     *
+     * @hide
+     */
+    public static final String DRIVING_SAFETY_REGION_ALL = "android.car.drivingsafetyregion.all";
+
+    /**
+     * Metadata which Activity can use to specify the driving safety regions it is supporting.
+     *
+     * <p>Definition of driving safety region is car OEM specific for now and only OEM apps
+     * should use this. If there are multiple regions, it should be comma separated. Not specifying
+     * this means supporting all regions.
+     *
+     * <p>Some examples are:
+     *   <meta-data android:name="android.car.drivingsafetyregions"
+     *   android:value="com.android.drivingsafetyregion.1,com.android.drivingsafetyregion.2"/>
+     *
+     * @hide
+     */
+    public static final String DRIVING_SAFETY_ACTIVITY_METADATA_REGIONS =
+            "android.car.drivingsafetyregions";
+
+    /**
+     * Internal error code for throwing {@code NameNotFoundException} from service.
+     *
+     * @hide
+     */
+    public static final int ERROR_CODE_NO_PACKAGE = -100;
+
     /** @hide */
     @IntDef(flag = true,
             value = {FLAG_SET_POLICY_WAIT_FOR_CHANGE, FLAG_SET_POLICY_ADD, FLAG_SET_POLICY_REMOVE})
@@ -242,4 +280,108 @@
             return handleRemoteExceptionFromCarService(e, false);
         }
     }
+
+    /**
+     * Returns the current driving safety region of the system. It will return OEM specific regions
+     * or {@link #DRIVING_SAFETY_REGION_ALL} when all regions are supported.
+     *
+     * <p> System's driving safety region is static and does not change until system restarts.
+     *
+     * @hide
+     */
+    @RequiresPermission(anyOf = {PERMISSION_CONTROL_APP_BLOCKING,
+            Car.PERMISSION_CAR_DRIVING_STATE})
+    @NonNull
+    public String getCurrentDrivingSafetyRegion() {
+        try {
+            return mService.getCurrentDrivingSafetyRegion();
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, DRIVING_SAFETY_REGION_ALL);
+        }
+    }
+
+    /**
+     * Enables or disables bypassing of unsafe {@code Activity} blocking for a specific
+     * {@code Activity} temporarily.
+     *
+     * <p> Enabling bypassing only lasts until the user stops using the car or until a user
+     * switching happens. Apps like launcher may ask user's consent to bypass. Note that bypassing
+     * is done for the package for all android users including the current user and user 0.
+     * <p> If bypassing is disabled and if the unsafe app is in foreground with driving state, the
+     * app will be immediately blocked.
+     *
+     * @param packageName Target package name.
+     * @param activityClassName Target Activity name (in full class name).
+     * @param bypass Bypass {@code Activity} blocking when true. Do not bypass anymore when false.
+     * @param userId User Id where the package is installed. Even if the bypassing is enabled for
+     *               all android users, the package should be available for the specified user id.
+     *
+     * @throws NameNotFoundException If the given package / Activity class does not exist for the
+     *         user.
+     *
+     * @hide
+     */
+    @RequiresPermission(allOf = {PERMISSION_CONTROL_APP_BLOCKING,
+            android.Manifest.permission.QUERY_ALL_PACKAGES})
+    public void controlTemporaryActivityBlockingBypassingAsUser(String packageName,
+            String activityClassName, boolean bypass, @UserIdInt int userId)
+            throws NameNotFoundException {
+        try {
+            mService.controlOneTimeActivityBlockingBypassingAsUser(packageName, activityClassName,
+                    bypass, userId);
+        } catch (ServiceSpecificException e) {
+            handleServiceSpecificFromCarService(e, packageName, activityClassName, userId);
+        } catch (RemoteException e) {
+            handleRemoteExceptionFromCarService(e);
+        }
+    }
+
+    /**
+     * Returns all supported driving safety regions for the given Activity. If the Activity supports
+     * all regions, it will only include {@link #DRIVING_SAFETY_REGION_ALL}.
+     *
+     * <p> The permission specification requires {@code PERMISSION_CONTROL_APP_BLOCKING} and
+     * {@code QUERY_ALL_PACKAGES} but this API will also work if the client has
+     * {@link Car#PERMISSION_CAR_DRIVING_STATE} and {@code QUERY_ALL_PACKAGES} permissions.
+     *
+     * @param packageName Target package name.
+     * @param activityClassName Target Activity name (in full class name).
+     * @param userId Android user Id to check the package.
+     *
+     * @return Empty list if the Activity does not support driving safety (=no
+     *         {@code distractionOptimized} metadata). Otherwise returns full list of all supported
+     *         regions.
+     *
+     * @throws NameNotFoundException If the given package / Activity class does not exist for the
+     *         user.
+     *
+     * @hide
+     */
+    @RequiresPermission(allOf = {PERMISSION_CONTROL_APP_BLOCKING,
+            android.Manifest.permission.QUERY_ALL_PACKAGES})
+    @NonNull
+    public List<String> getSupportedDrivingSafetyRegionsForActivityAsUser(String packageName,
+            String activityClassName, @UserIdInt int userId) throws NameNotFoundException {
+        try {
+            return mService.getSupportedDrivingSafetyRegionsForActivityAsUser(packageName,
+                    activityClassName, userId);
+        } catch (ServiceSpecificException e) {
+            handleServiceSpecificFromCarService(e, packageName, activityClassName, userId);
+        } catch (RemoteException e) {
+            return handleRemoteExceptionFromCarService(e, Collections.EMPTY_LIST);
+        }
+        return Collections.EMPTY_LIST; // cannot reach here but the compiler complains.
+    }
+
+    private void handleServiceSpecificFromCarService(ServiceSpecificException e,
+            String packageName, String activityClassName, @UserIdInt int userId)
+            throws NameNotFoundException {
+        if (e.errorCode == ERROR_CODE_NO_PACKAGE) {
+            throw new NameNotFoundException(
+                    "cannot find " + packageName + "/" + activityClassName + " for user id:"
+                            + userId);
+        }
+        // don't know what this is
+        throw new IllegalStateException(e);
+    }
 }
diff --git a/car-lib/src/android/car/content/pm/ICarPackageManager.aidl b/car-lib/src/android/car/content/pm/ICarPackageManager.aidl
index b8261f2..b0bdc7c 100644
--- a/car-lib/src/android/car/content/pm/ICarPackageManager.aidl
+++ b/car-lib/src/android/car/content/pm/ICarPackageManager.aidl
@@ -29,4 +29,9 @@
     void setEnableActivityBlocking(boolean enable) = 4;
     void restartTask(int taskId) = 5;
     boolean isPendingIntentDistractionOptimized(in PendingIntent pendingIntent) = 6;
+    String getCurrentDrivingSafetyRegion() = 7;
+    void controlOneTimeActivityBlockingBypassingAsUser(String packageName, String activityClassName,
+            boolean bypass, int userId) = 8;
+    List<String> getSupportedDrivingSafetyRegionsForActivityAsUser(String packageName,
+            String activityClassName, int userId) = 9;
 }
diff --git a/service/src/com/android/car/CarShellCommand.java b/service/src/com/android/car/CarShellCommand.java
index 2e16d10..f1fec38 100644
--- a/service/src/com/android/car/CarShellCommand.java
+++ b/service/src/com/android/car/CarShellCommand.java
@@ -41,6 +41,7 @@
 import android.car.Car;
 import android.car.CarOccupantZoneManager;
 import android.car.VehiclePropertyIds;
+import android.car.content.pm.CarPackageManager;
 import android.car.input.CarInputManager;
 import android.car.input.CustomInputEvent;
 import android.car.input.RotaryEvent;
@@ -205,6 +206,9 @@
     private static final String COMMAND_WATCHDOG_CONTROL_PROCESS_HEALTH_CHECK =
             "watchdog-control-health-check";
 
+    private static final String COMMAND_DRIVING_SAFETY_SET_REGION =
+            "set-drivingsafety-region";
+
     private static final String[] CREATE_OR_MANAGE_USERS_PERMISSIONS = new String[] {
             android.Manifest.permission.CREATE_USERS,
             android.Manifest.permission.MANAGE_USERS
@@ -637,6 +641,10 @@
         pw.printf("\t%s enable|disable\n", COMMAND_WATCHDOG_CONTROL_PROCESS_HEALTH_CHECK);
         pw.println("\t  Enables/disables car watchdog process health check.");
         pw.println("\t  Set to true to disable the process health check.");
+
+        pw.printf("\t%s [REGION_STRING]", COMMAND_DRIVING_SAFETY_SET_REGION);
+        pw.println("\t  Set driving safety region.");
+        pw.println("\t  Skipping REGION_STRING leads into resetting to all regions");
     }
 
     private static int showInvalidArguments(IndentingPrintWriter pw) {
@@ -972,6 +980,9 @@
             case COMMAND_WATCHDOG_CONTROL_PROCESS_HEALTH_CHECK:
                 controlWatchdogProcessHealthCheck(args, writer);
                 break;
+            case COMMAND_DRIVING_SAFETY_SET_REGION:
+                setDrivingSafetyRegion(args, writer);
+                break;
             default:
                 writer.println("Unknown command: \"" + cmd + "\"");
                 showHelp(writer);
@@ -2155,6 +2166,17 @@
         }
     }
 
+    private void setDrivingSafetyRegion(String[] args, IndentingPrintWriter writer) {
+        if (args.length != 1 && args.length != 2) {
+            showInvalidArguments(writer);
+            return;
+        }
+        String region = args.length == 2 ? args[1] : CarPackageManager.DRIVING_SAFETY_REGION_ALL;
+        writer.println("Set driving safety region to:" + region);
+        CarLocalServices.getService(CarPackageManagerService.class).resetDrivingSafetyRegion(
+                region);
+    }
+
     private void getRearviewCameraId(IndentingPrintWriter writer) {
         writer.printf("CarEvsService is using %s for the rearview.\n",
                 mCarEvsService.getRearviewCameraIdFromCommand());
diff --git a/service/src/com/android/car/pm/CarAppMetadataReader.java b/service/src/com/android/car/pm/CarAppMetadataReader.java
index 2b67f25..0e7c136 100644
--- a/service/src/com/android/car/pm/CarAppMetadataReader.java
+++ b/service/src/com/android/car/pm/CarAppMetadataReader.java
@@ -15,19 +15,25 @@
  */
 package com.android.car.pm;
 
+import static android.car.content.pm.CarPackageManager.DRIVING_SAFETY_ACTIVITY_METADATA_REGIONS;
+
+import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.car.content.pm.CarPackageManager;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.Bundle;
-import android.util.Log;
 import android.util.Slog;
 
 import com.android.car.CarLog;
 
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -49,19 +55,13 @@
     /** Name of the meta-data attribute of the Activity that denotes distraction optimized */
     private static final String DO_METADATA_ATTRIBUTE = "distractionOptimized";
 
-    /**
-     * Parses the given package and returns Distraction Optimized information, if present.
-     *
-     * @return Array of DO activity names in the given package
-     */
-    @Nullable
-    public static String[] findDistractionOptimizedActivitiesAsUser(Context context,
-            String packageName, int userId) throws NameNotFoundException {
-        final PackageManager pm = context.getPackageManager();
+    private static final List<String> ALL_REGION_ONLY = Collections.singletonList(
+            CarPackageManager.DRIVING_SAFETY_REGION_ALL);
 
-        // Check if any of the activities in the package are DO by checking all the
-        // <activity> elements. MATCH_DISABLED_COMPONENTS is included so that we are immediately
-        // prepared to respond to any components that toggle from disabled to enabled.
+    @Nullable
+    private static ActivityInfo[] getAllActivitiesForPackageAsUser(Context context,
+            String packageName, @UserIdInt int userId)  throws NameNotFoundException {
+        final PackageManager pm = context.getPackageManager();
         PackageInfo pkgInfo =
                 pm.getPackageInfoAsUser(
                         packageName, PackageManager.GET_ACTIVITIES
@@ -74,18 +74,43 @@
             return null;
         }
 
-        ActivityInfo[] activities = pkgInfo.activities;
+        return pkgInfo.activities;
+    }
+
+    /**
+     * Parses the given package and returns Distraction Optimized information, if present.
+     *
+     * @return Array of DO activity names in the given package
+     */
+    @Nullable
+    public static String[] findDistractionOptimizedActivitiesAsUser(Context context,
+            String packageName, @UserIdInt int userId, @NonNull String drivingSafetyRegion)
+            throws NameNotFoundException {
+
+
+        // Check if any of the activities in the package are DO by checking all the
+        // <activity> elements. MATCH_DISABLED_COMPONENTS is included so that we are immediately
+        // prepared to respond to any components that toggle from disabled to enabled.
+        ActivityInfo[] activities = getAllActivitiesForPackageAsUser(context, packageName, userId);
         if (activities == null) {
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
+            if (CarPackageManagerService.DBG) {
                 Slog.d(TAG, "Null Activities for " + packageName);
             }
             return null;
         }
         List<String> optimizedActivityList = new ArrayList();
         for (ActivityInfo activity : activities) {
-            Bundle mData = activity.metaData;
-            if (mData != null && mData.getBoolean(DO_METADATA_ATTRIBUTE, false)) {
-                if (Log.isLoggable(TAG, Log.DEBUG)) {
+            Bundle metaData = activity.metaData;
+            if (metaData == null) {
+                continue;
+            }
+            String regionString = metaData.getString(DRIVING_SAFETY_ACTIVITY_METADATA_REGIONS,
+                    CarPackageManager.DRIVING_SAFETY_REGION_ALL);
+            if (!isRegionSupported(regionString, drivingSafetyRegion)) {
+                continue;
+            }
+            if (metaData.getBoolean(DO_METADATA_ATTRIBUTE, false)) {
+                if (CarPackageManagerService.DBG) {
                     Slog.d(TAG,
                             "DO Activity:" + activity.packageName + "/" + activity.name);
                 }
@@ -97,4 +122,66 @@
         }
         return optimizedActivityList.toArray(new String[optimizedActivityList.size()]);
     }
+
+    /**
+     * Check {@link CarPackageManager#getSupportedDrivingSafetyRegionsForActivityAsUser(
+     * String, String, int)}.
+     */
+    public static List<String> getSupportedDrivingSafetyRegionsForActivityAsUser(Context context,
+            String packageName, String activityClassName, @UserIdInt int userId)
+            throws NameNotFoundException {
+        ActivityInfo[] activities = getAllActivitiesForPackageAsUser(context, packageName, userId);
+        if (activities == null) {
+            throw new NameNotFoundException();
+        }
+        for (ActivityInfo info: activities) {
+            if (!info.name.equals(activityClassName)) {
+                continue;
+            }
+            // Found activity
+            Bundle metaData = info.metaData;
+            if (metaData == null) {
+                return Collections.EMPTY_LIST;
+            }
+            if (!metaData.getBoolean(DO_METADATA_ATTRIBUTE, false)) {
+                // no distractionOptimized, so region metadata does not matter.
+                return Collections.EMPTY_LIST;
+            }
+            String regionString = metaData.getString(DRIVING_SAFETY_ACTIVITY_METADATA_REGIONS,
+                    CarPackageManager.DRIVING_SAFETY_REGION_ALL);
+            String[] regions = regionString.split(",");
+            for (String region: regions) {
+                if (CarPackageManager.DRIVING_SAFETY_REGION_ALL.equals(region)) {
+                    return ALL_REGION_ONLY;
+                }
+            }
+            return Arrays.asList(regions);
+        }
+        throw new NameNotFoundException();
+    }
+
+    private static boolean isRegionSupported(String regionString, String currentRegion) {
+        if (regionString.isEmpty()) { // not specified means all regions.
+            return true;
+        }
+        if (currentRegion.equals(CarPackageManager.DRIVING_SAFETY_REGION_ALL)) {
+            return true;
+        }
+        String[] regions = regionString.split(",");
+        for (String region: regions) {
+            if (CarPackageManager.DRIVING_SAFETY_REGION_ALL.equals(region)) {
+                return true;
+            }
+            if (currentRegion.equals(region)) {
+                return true;
+            }
+        }
+        // valid regions but does not match currentRegion.
+        if (CarPackageManagerService.DBG) {
+            Slog.d(TAG,
+                    "isRegionSupported not supported, regionString:" + regionString
+                            + " region:" + currentRegion);
+        }
+        return false;
+    }
 }
diff --git a/service/src/com/android/car/pm/CarPackageManagerService.java b/service/src/com/android/car/pm/CarPackageManagerService.java
index 10288b1..e8e4315 100644
--- a/service/src/com/android/car/pm/CarPackageManagerService.java
+++ b/service/src/com/android/car/pm/CarPackageManagerService.java
@@ -32,6 +32,11 @@
 import android.car.content.pm.ICarPackageManager;
 import android.car.drivingstate.CarUxRestrictions;
 import android.car.drivingstate.ICarUxRestrictionsChangeListener;
+import android.car.hardware.power.CarPowerPolicy;
+import android.car.hardware.power.CarPowerPolicyFilter;
+import android.car.hardware.power.ICarPowerPolicyListener;
+import android.car.hardware.power.PowerComponent;
+import android.car.user.CarUserManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -57,6 +62,8 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.ArraySet;
@@ -69,6 +76,7 @@
 import android.view.Display;
 import android.view.DisplayAddress;
 
+import com.android.car.CarLocalServices;
 import com.android.car.CarLog;
 import com.android.car.CarServiceBase;
 import com.android.car.CarServiceUtils;
@@ -76,6 +84,8 @@
 import com.android.car.R;
 import com.android.car.SystemActivityMonitoringService;
 import com.android.car.SystemActivityMonitoringService.TopTaskInfoContainer;
+import com.android.car.power.CarPowerManagementService;
+import com.android.car.user.CarUserService;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.utils.Slogf;
@@ -99,6 +109,8 @@
 
 public class CarPackageManagerService extends ICarPackageManager.Stub implements CarServiceBase {
 
+    static final boolean DBG = false;
+
     private static final String TAG = CarLog.tagFor(CarPackageManagerService.class);
 
     // Delimiters to parse packages and activities in the configuration XML resource.
@@ -107,6 +119,9 @@
     private static final int LOG_SIZE = 20;
     private static final String[] WINDOW_DUMP_ARGUMENTS = new String[]{"windows"};
 
+    private static final String PROPERTY_RO_DRIVING_SAFETY_REGION =
+            "ro.android.car.drivingsafetyregion";
+
     private final Context mContext;
     private final SystemActivityMonitoringService mSystemActivityMonitoringService;
     private final PackageManager mPackageManager;
@@ -153,8 +168,15 @@
     @GuardedBy("mLock")
     private final LinkedList<CarAppBlockingPolicy> mWaitingPolicies = new LinkedList<>();
 
+    @GuardedBy("mLock")
+    private String mCurrentDrivingSafetyRegion = CarPackageManager.DRIVING_SAFETY_REGION_ALL;
+    // Package name + '/' + className format
+    @GuardedBy("mLock")
+    private final ArraySet<String> mTempAllowedActivities = new ArraySet<>();
+
     private final CarUxRestrictionsManagerService mCarUxRestrictionsService;
-    private boolean mEnableActivityBlocking;
+    private final boolean mEnableActivityBlocking;
+
     private final ComponentName mActivityBlockingActivity;
     private final boolean mPreventTemplatedAppsFromShowingDialog;
     private final String mTemplateActivityClassName;
@@ -211,6 +233,32 @@
      */
     public static final String BLOCKING_INTENT_EXTRA_DISPLAY_ID = "display_id";
 
+    private final CarUserManager.UserLifecycleListener mUserLifecycleListener =
+            new CarUserManager.UserLifecycleListener() {
+                @Override
+                public void onEvent(CarUserManager.UserLifecycleEvent event) {
+                    if (event.getEventType()
+                            == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
+                        synchronized (mLock) {
+                            resetTempAllowedActivitiesLocked();
+                        }
+                    }
+                }
+            };
+
+    private final ICarPowerPolicyListener mDisplayPowerPolicyListener =
+            new ICarPowerPolicyListener.Stub() {
+                @Override
+                public void onPolicyChanged(CarPowerPolicy policy,
+                        CarPowerPolicy accumulatedPolicy) {
+                    if (!policy.isComponentEnabled(PowerComponent.DISPLAY)) {
+                        synchronized (mLock) {
+                            resetTempAllowedActivitiesLocked();
+                        }
+                    }
+                }
+            };
+
     public CarPackageManagerService(Context context,
             CarUxRestrictionsManagerService uxRestrictionsService,
             SystemActivityMonitoringService systemActivityMonitoringService) {
@@ -256,13 +304,92 @@
         mSystemActivityMonitoringService.restartTask(taskId);
     }
 
-    private void doSetAppBlockingPolicy(String packageName, CarAppBlockingPolicy policy,
-            int flags) {
+    @Override
+    public String getCurrentDrivingSafetyRegion() {
+        assertAppBlockingOrDrivingStatePermission();
+        synchronized (mLock) {
+            return mCurrentDrivingSafetyRegion;
+        }
+    }
+
+    private String getComponentNameString(String packageName, String className) {
+        return packageName + '/' + className;
+    }
+
+    @Override
+    public void controlOneTimeActivityBlockingBypassingAsUser(String packageName,
+            String activityClassName, boolean bypass, @UserIdInt int userId) {
+        assertAppBlockingPermission();
+        if (!callerCanQueryPackage(packageName)) {
+            throw new SecurityException("cannot query other package");
+        }
+        try {
+            // Read this to check the validity of pkg / activity name. Not checking this can allow
+            // bad apps to be allowed later.
+            CarAppMetadataReader.getSupportedDrivingSafetyRegionsForActivityAsUser(mContext,
+                    packageName, activityClassName, userId);
+        } catch (NameNotFoundException e) {
+            throw new ServiceSpecificException(CarPackageManager.ERROR_CODE_NO_PACKAGE,
+                    e.getMessage());
+        }
+        String componentName = getComponentNameString(packageName, activityClassName);
+        synchronized (mLock) {
+            if (bypass) {
+                mTempAllowedActivities.add(componentName);
+            } else {
+                mTempAllowedActivities.remove(componentName);
+            }
+        }
+        if (!bypass) { // block top activities if bypassing is disabled.
+            blockTopActivitiesIfNecessary();
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void resetTempAllowedActivitiesLocked() {
+        mTempAllowedActivities.clear();
+    }
+
+    @Override
+    public List<String> getSupportedDrivingSafetyRegionsForActivityAsUser(String packageName,
+            String activityClassName, @UserIdInt int userId) {
+        assertAppBlockingOrDrivingStatePermission();
+        if (!callerCanQueryPackage(packageName)) {
+            throw new SecurityException("cannot query other package");
+        }
+        long token = Binder.clearCallingIdentity();
+        try {
+            return CarAppMetadataReader.getSupportedDrivingSafetyRegionsForActivityAsUser(mContext,
+                    packageName, activityClassName, userId);
+        } catch (NameNotFoundException e) {
+            throw new ServiceSpecificException(CarPackageManager.ERROR_CODE_NO_PACKAGE,
+                    e.getMessage());
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
+    private void assertAppBlockingOrDrivingStatePermission() {
+        if (mContext.checkCallingOrSelfPermission(Car.PERMISSION_CONTROL_APP_BLOCKING)
+                != PackageManager.PERMISSION_GRANTED && mContext.checkCallingOrSelfPermission(
+                Car.PERMISSION_CAR_DRIVING_STATE) != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException(
+                    "requires permission " + Car.PERMISSION_CONTROL_APP_BLOCKING + " or "
+                            + Car.PERMISSION_CAR_DRIVING_STATE);
+        }
+    }
+
+    private void assertAppBlockingPermission() {
         if (mContext.checkCallingOrSelfPermission(Car.PERMISSION_CONTROL_APP_BLOCKING)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException(
                     "requires permission " + Car.PERMISSION_CONTROL_APP_BLOCKING);
         }
+    }
+
+    private void doSetAppBlockingPolicy(String packageName, CarAppBlockingPolicy policy,
+            int flags) {
+        assertAppBlockingPermission();
         CarServiceUtils.assertPackageName(mContext, packageName);
         if (policy == null) {
             throw new IllegalArgumentException("policy cannot be null");
@@ -302,6 +429,11 @@
                 Slog.d(TAG, "isActivityDistractionOptimized" + dumpPoliciesLocked(false));
             }
 
+            if (mTempAllowedActivities.contains(getComponentNameString(packageName,
+                    className))) {
+                return true;
+            }
+
             for (int i = mTopActivityWithDialogPerDisplay.size() - 1; i >= 0; i--) {
                 ComponentName activityWithDialog = mTopActivityWithDialogPerDisplay.get(
                         mTopActivityWithDialogPerDisplay.keyAt(i));
@@ -493,13 +625,24 @@
 
     @Override
     public void init() {
+        String safetyRegion = SystemProperties.get(PROPERTY_RO_DRIVING_SAFETY_REGION, "");
         synchronized (mLock) {
+            setDrivingSafetyRegionWithCheckLocked(safetyRegion);
             mHandler.requestInit();
         }
+        CarLocalServices.getService(CarUserService.class).addUserLifecycleListener(
+                mUserLifecycleListener);
+        CarLocalServices.getService(CarPowerManagementService.class).addPowerPolicyListener(
+                new CarPowerPolicyFilter.Builder().setComponents(PowerComponent.DISPLAY).build(),
+                mDisplayPowerPolicyListener);
     }
 
     @Override
     public void release() {
+        CarLocalServices.getService(CarPowerManagementService.class).removePowerPolicyListener(
+                mDisplayPowerPolicyListener);
+        CarLocalServices.getService(CarUserService.class).removeUserLifecycleListener(
+                mUserLifecycleListener);
         synchronized (mLock) {
             mHandler.requestRelease();
             // wait for release do be done. This guarantees that init is done.
@@ -519,6 +662,7 @@
                 mProxies.clear();
             }
             mWaitingPolicies.clear();
+            resetTempAllowedActivitiesLocked();
             mLock.notifyAll();
         }
         mContext.unregisterReceiver(mPackageParsingEventReceiver);
@@ -529,6 +673,28 @@
         }
     }
 
+    @GuardedBy("mLock")
+    private void setDrivingSafetyRegionWithCheckLocked(String region) {
+        if (region.isEmpty()) {
+            mCurrentDrivingSafetyRegion = CarPackageManager.DRIVING_SAFETY_REGION_ALL;
+        } else {
+            mCurrentDrivingSafetyRegion = region;
+        }
+    }
+
+    /**
+     * Reset driving stat and all dynamically added allow list so that region information for
+     * all packages are reset. This also resets one time allow list.
+     */
+    public void resetDrivingSafetyRegion(@NonNull String region) {
+        synchronized (mLock) {
+            setDrivingSafetyRegionWithCheckLocked(region);
+            resetTempAllowedActivitiesLocked();
+            mActivityAllowlistMap.clear();
+            mActivityDenylistPackages.clear();
+        }
+    }
+
     // run from HandlerThread
     private void doHandleInit() {
         startAppBlockingPolicies();
@@ -771,9 +937,8 @@
         }
 
         try {
-            String[] doActivities =
-                    CarAppMetadataReader.findDistractionOptimizedActivitiesAsUser(
-                            mContext, info.packageName, userId);
+            String[] doActivities = findDistractionOptimizedActivitiesAsUser(info.packageName,
+                    userId);
             if (doActivities != null) {
                 // Some of the activities in this app are Distraction Optimized.
                 if (Log.isLoggable(TAG, Log.DEBUG)) {
@@ -842,10 +1007,14 @@
 
         synchronized (mLock) {
             if (wrapper != null) {
-                Slog.d(TAG, "Package: " + packageName + " added in allowlist.");
+                if (DBG) {
+                    Slog.d(TAG, "Package: " + packageName + " added in allowlist.");
+                }
                 mActivityAllowlistMap.put(packageName, wrapper);
             } else {
-                Slog.d(TAG, "Package: " + packageName + " added in denylist.");
+                if (DBG) {
+                    Slog.d(TAG, "Package: " + packageName + " added in denylist.");
+                }
                 mActivityDenylistPackages.add(packageName);
             }
         }
@@ -1026,9 +1195,9 @@
         synchronized (mLock) {
             writer.println("*CarPackageManagerService*");
             writer.println("mEnableActivityBlocking:" + mEnableActivityBlocking);
-            writer.println("mPreventTemplatedAppsFromShowingDialog"
+            writer.println("mPreventTemplatedAppsFromShowingDialog:"
                     + mPreventTemplatedAppsFromShowingDialog);
-            writer.println("mTemplateActivityClassName" + mTemplateActivityClassName);
+            writer.println("mTemplateActivityClassName:" + mTemplateActivityClassName);
             List<String> restrictions = new ArrayList<>(mUxRestrictionsListeners.size());
             for (int i = 0; i < mUxRestrictionsListeners.size(); i++) {
                 int displayId = mUxRestrictionsListeners.keyAt(i);
@@ -1040,6 +1209,10 @@
             writer.println(" Blocked activity log:");
             mBlockedActivityLogs.dump(writer);
             writer.print(dumpPoliciesLocked(true));
+            writer.print("mCurrentDrivingSafetyRegion:");
+            writer.println(mCurrentDrivingSafetyRegion);
+            writer.print("mTempAllowedActivities:");
+            writer.println(mTempAllowedActivities);
         }
     }
 
@@ -1158,13 +1331,11 @@
         if (allowed) {
             return;
         }
-        synchronized (mLock) {
-            if (!mEnableActivityBlocking) {
-                Slog.d(TAG, "Current activity " + topTask.topActivity
-                        + " not allowed, blocking disabled. Number of tasks in stack:"
-                        + topTask.taskInfo.childTaskIds.length);
-                return;
-            }
+        if (!mEnableActivityBlocking) {
+            Slog.d(TAG, "Current activity " + topTask.topActivity
+                    + " not allowed, blocking disabled. Number of tasks in stack:"
+                    + topTask.taskInfo.childTaskIds.length);
+            return;
         }
         if (Log.isLoggable(TAG, Log.DEBUG)) {
             Slog.d(TAG, "Current activity " + topTask.topActivity
@@ -1343,13 +1514,23 @@
     @Nullable
     public String[] getDistractionOptimizedActivities(String pkgName) {
         try {
-            return CarAppMetadataReader.findDistractionOptimizedActivitiesAsUser(mContext, pkgName,
+            return findDistractionOptimizedActivitiesAsUser(pkgName,
                     mActivityManager.getCurrentUser());
         } catch (NameNotFoundException e) {
             return null;
         }
     }
 
+    private String[] findDistractionOptimizedActivitiesAsUser(String pkgName, int userId)
+            throws NameNotFoundException {
+        String regionString;
+        synchronized (mLock) {
+            regionString = mCurrentDrivingSafetyRegion;
+        }
+        return CarAppMetadataReader.findDistractionOptimizedActivitiesAsUser(mContext, pkgName,
+                userId, regionString);
+    }
+
     /**
      * Reading policy and setting policy can take time. Run it in a separate handler thread.
      */
diff --git a/tests/android_car_api_test/AndroidManifest.xml b/tests/android_car_api_test/AndroidManifest.xml
index 7ae6fde..3e91a40 100644
--- a/tests/android_car_api_test/AndroidManifest.xml
+++ b/tests/android_car_api_test/AndroidManifest.xml
@@ -34,6 +34,44 @@
                 <action android:name="android.intent.action.MAIN"/>
             </intent-filter>
         </activity>
+        <activity android:name=".TestDrivingSafetyAllRegionActivity"
+                  android:exported="true">
+            <meta-data android:name="distractionOptimized" android:value="true"/>
+        </activity>
+        <activity android:name=".TestDrivingSafetyExplicitAllRegionsActivity"
+                  android:exported="true">
+            <meta-data android:name="distractionOptimized" android:value="true"/>
+            <!-- not necessary as all region is the default state but this is still valid -->
+            <meta-data android:name="android.car.drivingsafetyregions"
+                       android:value="android.car.drivingsafetyregion.all"/>
+        </activity>
+        <activity android:name=".TestDrivingSafetyOneRegionActivity"
+                  android:exported="true">
+            <meta-data android:name="distractionOptimized" android:value="true"/>
+            <meta-data android:name="android.car.drivingsafetyregions"
+                       android:value="com.android.car.test.drivingsafetyregion.1"/>
+        </activity>
+        <activity android:name=".TestDrivingSafetyTwoRegionsActivity"
+                  android:exported="true">
+            <meta-data android:name="distractionOptimized" android:value="true"/>
+            <meta-data android:name="android.car.drivingsafetyregions"
+                       android:value="com.android.car.test.drivingsafetyregion.1,com.android.car.test.drivingsafetyregion.2"/>
+        </activity>
+        <activity android:name=".TestDrivingSafetyRegion1OnlyActivity"
+                  android:exported="true">
+            <!--No distractionOptimized, so this app will be unsafe. -->
+            <meta-data android:name="android.car.drivingsafetyregions"
+                       android:value="com.android.test.drivingsafetyregion.1"/>
+        </activity>
+        <activity android:name=".TestDrivingSafetyRegionAllOnlyActivity"
+                  android:exported="true">
+            <!--No distractionOptimized, so this app will be unsafe. -->
+            <meta-data android:name="android.car.drivingsafetyregions"
+                       android:value="android.car.drivingsafetyregion.all"/>
+        </activity>
+        <activity android:name=".TestDrivingSafetyRegionNoMetadataActivity"
+                  android:exported="true">
+        </activity>
         <service android:name=".CarProjectionManagerTest$TestService"
              android:exported="true"/>
     </application>
diff --git a/tests/android_car_api_test/src/android/car/apitest/DrivingSafetyRegionTest.java b/tests/android_car_api_test/src/android/car/apitest/DrivingSafetyRegionTest.java
new file mode 100644
index 0000000..473a8b1
--- /dev/null
+++ b/tests/android_car_api_test/src/android/car/apitest/DrivingSafetyRegionTest.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2021 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.car.apitest;
+
+import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeTrue;
+import static org.testng.Assert.assertThrows;
+
+import android.app.ActivityManager;
+import android.car.Car;
+import android.car.content.pm.CarPackageManager;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.List;
+
+@SmallTest
+public class DrivingSafetyRegionTest extends CarApiTestBase {
+    private static final String REGION1 = "com.android.car.test.drivingsafetyregion.1";
+    private static final String REGION2 = "com.android.car.test.drivingsafetyregion.2";
+    private static final String REGION3 = "com.android.car.test.drivingsafetyregion.3";
+
+    private static final String TEST_PACKAGE_NAME = "android.car.apitest";
+
+    private CarPackageManager mCarPackageManager;
+    private String mOriginalDrivingSafetyRegion = null;
+
+    private final int mCurrentUser = ActivityManager.getCurrentUser();
+
+    @Before
+    public void setUp() {
+        mCarPackageManager = (CarPackageManager) getCar().getCarManager(Car.PACKAGE_SERVICE);
+
+        assertThat(mCarPackageManager).isNotNull();
+
+        mOriginalDrivingSafetyRegion = mCarPackageManager.getCurrentDrivingSafetyRegion();
+
+        assertThat(mOriginalDrivingSafetyRegion).isNotNull();
+
+        // cannot run this in user build as region change is not allowed in user build for shell.
+        assumeTrue(Build.IS_ENG || Build.IS_USERDEBUG);
+    }
+
+    @After
+    public void tearDown() {
+        if (mOriginalDrivingSafetyRegion != null) {
+            setDrivingSafetyRegion(mOriginalDrivingSafetyRegion);
+        }
+    }
+
+    @Test
+    public void testImplicitAllRegions() throws Exception {
+        doTestAllRegions(TestDrivingSafetyAllRegionActivity.class.getName());
+    }
+
+    @Test
+    public void testExplicitAllRegions() throws Exception {
+        doTestAllRegions(TestDrivingSafetyExplicitAllRegionsActivity.class.getName());
+    }
+
+    private void doTestAllRegions(String activityClassName) throws Exception {
+        assertThat(mCarPackageManager.isActivityDistractionOptimized(TEST_PACKAGE_NAME,
+                activityClassName)).isTrue();
+
+        List<String> regions = mCarPackageManager.getSupportedDrivingSafetyRegionsForActivityAsUser(
+                TEST_PACKAGE_NAME, activityClassName, ActivityManager.getCurrentUser());
+
+        assertThat(regions).containsExactly(CarPackageManager.DRIVING_SAFETY_REGION_ALL);
+
+        // all region app should be safe always regardless of bypassing / region change
+        setDrivingSafetyRegion(REGION1);
+
+        assertThat(mCarPackageManager.isActivityDistractionOptimized(TEST_PACKAGE_NAME,
+                activityClassName)).isTrue();
+
+        mCarPackageManager.controlTemporaryActivityBlockingBypassingAsUser(TEST_PACKAGE_NAME,
+                activityClassName, true, mCurrentUser);
+
+        assertThat(mCarPackageManager.isActivityDistractionOptimized(TEST_PACKAGE_NAME,
+                activityClassName)).isTrue();
+
+        mCarPackageManager.controlTemporaryActivityBlockingBypassingAsUser(TEST_PACKAGE_NAME,
+                activityClassName, false, mCurrentUser);
+
+        assertThat(mCarPackageManager.isActivityDistractionOptimized(TEST_PACKAGE_NAME,
+                activityClassName)).isTrue();
+    }
+
+    @Test
+    public void testOneRegionOnly() throws Exception {
+        String activityClassName = TestDrivingSafetyOneRegionActivity.class.getName();
+
+        List<String> regions = mCarPackageManager.getSupportedDrivingSafetyRegionsForActivityAsUser(
+                TEST_PACKAGE_NAME, activityClassName, ActivityManager.getCurrentUser());
+
+        assertThat(regions).containsExactly(REGION1);
+
+        setDrivingSafetyRegion(REGION1);
+
+        assertThat(mCarPackageManager.isActivityDistractionOptimized(TEST_PACKAGE_NAME,
+                activityClassName)).isTrue();
+
+        setDrivingSafetyRegion(REGION2);
+
+        assertThat(mCarPackageManager.isActivityDistractionOptimized(TEST_PACKAGE_NAME,
+                activityClassName)).isFalse();
+
+        mCarPackageManager.controlTemporaryActivityBlockingBypassingAsUser(TEST_PACKAGE_NAME,
+                activityClassName, true, mCurrentUser);
+
+        assertThat(mCarPackageManager.isActivityDistractionOptimized(TEST_PACKAGE_NAME,
+                activityClassName)).isTrue();
+
+        mCarPackageManager.controlTemporaryActivityBlockingBypassingAsUser(TEST_PACKAGE_NAME,
+                activityClassName, false, mCurrentUser);
+
+        assertThat(mCarPackageManager.isActivityDistractionOptimized(TEST_PACKAGE_NAME,
+                activityClassName)).isFalse();
+
+        setDrivingSafetyRegion(CarPackageManager.DRIVING_SAFETY_REGION_ALL);
+
+        assertThat(mCarPackageManager.isActivityDistractionOptimized(TEST_PACKAGE_NAME,
+                activityClassName)).isTrue();
+    }
+
+    @Test
+    public void testTwoRegionsOnly() throws Exception {
+        String activityClassName = TestDrivingSafetyTwoRegionsActivity.class.getName();
+
+        List<String> regions = mCarPackageManager.getSupportedDrivingSafetyRegionsForActivityAsUser(
+                TEST_PACKAGE_NAME, activityClassName, ActivityManager.getCurrentUser());
+
+        assertThat(regions).containsExactly(REGION1, REGION2);
+
+        setDrivingSafetyRegion(REGION1);
+
+        assertThat(mCarPackageManager.isActivityDistractionOptimized(TEST_PACKAGE_NAME,
+                activityClassName)).isTrue();
+
+        setDrivingSafetyRegion(REGION2);
+
+        assertThat(mCarPackageManager.isActivityDistractionOptimized(TEST_PACKAGE_NAME,
+                activityClassName)).isTrue();
+
+        setDrivingSafetyRegion(REGION3);
+
+        assertThat(mCarPackageManager.isActivityDistractionOptimized(TEST_PACKAGE_NAME,
+                activityClassName)).isFalse();
+
+        setDrivingSafetyRegion(CarPackageManager.DRIVING_SAFETY_REGION_ALL);
+
+        assertThat(mCarPackageManager.isActivityDistractionOptimized(TEST_PACKAGE_NAME,
+                activityClassName)).isTrue();
+    }
+
+    @Test
+    public void testRegion1OnlyActivity() throws Exception {
+        doTestRegionOnlyOrNoRegionCase(TestDrivingSafetyRegion1OnlyActivity.class.getName());
+    }
+
+    @Test
+    public void testRegionAllOnlyActivity() throws Exception {
+        doTestRegionOnlyOrNoRegionCase(TestDrivingSafetyRegionAllOnlyActivity.class.getName());
+    }
+
+    @Test
+    public void testRegionNoMetadataActivity() throws Exception {
+        doTestRegionOnlyOrNoRegionCase(TestDrivingSafetyRegionNoMetadataActivity.class.getName());
+    }
+
+    private void doTestRegionOnlyOrNoRegionCase(String activityClassName) throws Exception {
+        List<String> regions = mCarPackageManager.getSupportedDrivingSafetyRegionsForActivityAsUser(
+                TEST_PACKAGE_NAME, activityClassName, ActivityManager.getCurrentUser());
+
+        // not distraction optimized, so list should be empty.
+        assertThat(regions).isEmpty();
+
+        assertThat(mCarPackageManager.isActivityDistractionOptimized(TEST_PACKAGE_NAME,
+                activityClassName)).isFalse();
+
+        // should not be safe for any region.
+        setDrivingSafetyRegion(CarPackageManager.DRIVING_SAFETY_REGION_ALL);
+
+        assertThat(mCarPackageManager.isActivityDistractionOptimized(TEST_PACKAGE_NAME,
+                activityClassName)).isFalse();
+
+        setDrivingSafetyRegion(REGION1);
+
+        assertThat(mCarPackageManager.isActivityDistractionOptimized(TEST_PACKAGE_NAME,
+                activityClassName)).isFalse();
+
+        setDrivingSafetyRegion(REGION2);
+
+        assertThat(mCarPackageManager.isActivityDistractionOptimized(TEST_PACKAGE_NAME,
+                activityClassName)).isFalse();
+
+        mCarPackageManager.controlTemporaryActivityBlockingBypassingAsUser(TEST_PACKAGE_NAME,
+                activityClassName, true, mCurrentUser);
+
+        assertThat(mCarPackageManager.isActivityDistractionOptimized(TEST_PACKAGE_NAME,
+                activityClassName)).isTrue();
+
+        mCarPackageManager.controlTemporaryActivityBlockingBypassingAsUser(TEST_PACKAGE_NAME,
+                activityClassName, false, mCurrentUser);
+
+        assertThat(mCarPackageManager.isActivityDistractionOptimized(TEST_PACKAGE_NAME,
+                activityClassName)).isFalse();
+    }
+
+    @Test
+    public void testNoPackage() {
+        String noPkg = "NoSuchPackage";
+
+        assertThrows(PackageManager.NameNotFoundException.class,
+                () -> mCarPackageManager.getSupportedDrivingSafetyRegionsForActivityAsUser(
+                        noPkg, "", mCurrentUser));
+
+        assertThrows(PackageManager.NameNotFoundException.class,
+                () -> mCarPackageManager.controlTemporaryActivityBlockingBypassingAsUser(
+                        noPkg, "", true, mCurrentUser));
+    }
+
+    @Test
+    public void testNoActivity() {
+        String noSuchActivity = "NoSuchActivity";
+
+        assertThrows(PackageManager.NameNotFoundException.class,
+                () -> mCarPackageManager.getSupportedDrivingSafetyRegionsForActivityAsUser(
+                        TEST_PACKAGE_NAME, noSuchActivity, mCurrentUser));
+
+        assertThrows(PackageManager.NameNotFoundException.class,
+                () -> mCarPackageManager.controlTemporaryActivityBlockingBypassingAsUser(
+                        TEST_PACKAGE_NAME, noSuchActivity, true, mCurrentUser));
+    }
+
+    @Test
+    public void testResetEmptyRegion() {
+        setDrivingSafetyRegion(REGION1);
+
+        assertThat(mCarPackageManager.getCurrentDrivingSafetyRegion()).isEqualTo(REGION1);
+
+        // no arg means all
+        runShellCommand("cmd car_service set-drivingsafety-region");
+
+        assertThat(mCarPackageManager.getCurrentDrivingSafetyRegion()).isEqualTo(
+                CarPackageManager.DRIVING_SAFETY_REGION_ALL);
+    }
+
+    private void setDrivingSafetyRegion(String region) {
+        runShellCommand("cmd car_service set-drivingsafety-region  " + region);
+    }
+}
diff --git a/tests/android_car_api_test/src/android/car/apitest/TestDrivingSafetyAllRegionActivity.java b/tests/android_car_api_test/src/android/car/apitest/TestDrivingSafetyAllRegionActivity.java
new file mode 100644
index 0000000..48af4dd
--- /dev/null
+++ b/tests/android_car_api_test/src/android/car/apitest/TestDrivingSafetyAllRegionActivity.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 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.car.apitest;
+
+import android.app.Activity;
+
+public class TestDrivingSafetyAllRegionActivity extends Activity {
+}
diff --git a/tests/android_car_api_test/src/android/car/apitest/TestDrivingSafetyExplicitAllRegionsActivity.java b/tests/android_car_api_test/src/android/car/apitest/TestDrivingSafetyExplicitAllRegionsActivity.java
new file mode 100644
index 0000000..f369acc
--- /dev/null
+++ b/tests/android_car_api_test/src/android/car/apitest/TestDrivingSafetyExplicitAllRegionsActivity.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 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.car.apitest;
+
+import android.app.Activity;
+
+public class TestDrivingSafetyExplicitAllRegionsActivity extends Activity {
+}
diff --git a/tests/android_car_api_test/src/android/car/apitest/TestDrivingSafetyOneRegionActivity.java b/tests/android_car_api_test/src/android/car/apitest/TestDrivingSafetyOneRegionActivity.java
new file mode 100644
index 0000000..623e5e0
--- /dev/null
+++ b/tests/android_car_api_test/src/android/car/apitest/TestDrivingSafetyOneRegionActivity.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 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.car.apitest;
+
+import android.app.Activity;
+
+public class TestDrivingSafetyOneRegionActivity extends Activity {
+}
diff --git a/tests/android_car_api_test/src/android/car/apitest/TestDrivingSafetyRegion1OnlyActivity.java b/tests/android_car_api_test/src/android/car/apitest/TestDrivingSafetyRegion1OnlyActivity.java
new file mode 100644
index 0000000..2256330
--- /dev/null
+++ b/tests/android_car_api_test/src/android/car/apitest/TestDrivingSafetyRegion1OnlyActivity.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 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.car.apitest;
+
+import android.app.Activity;
+
+public class TestDrivingSafetyRegion1OnlyActivity extends Activity {
+}
diff --git a/tests/android_car_api_test/src/android/car/apitest/TestDrivingSafetyRegionAllOnlyActivity.java b/tests/android_car_api_test/src/android/car/apitest/TestDrivingSafetyRegionAllOnlyActivity.java
new file mode 100644
index 0000000..863d308
--- /dev/null
+++ b/tests/android_car_api_test/src/android/car/apitest/TestDrivingSafetyRegionAllOnlyActivity.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 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.car.apitest;
+
+import android.app.Activity;
+
+public class TestDrivingSafetyRegionAllOnlyActivity extends Activity {
+}
diff --git a/tests/android_car_api_test/src/android/car/apitest/TestDrivingSafetyRegionNoMetadataActivity.java b/tests/android_car_api_test/src/android/car/apitest/TestDrivingSafetyRegionNoMetadataActivity.java
new file mode 100644
index 0000000..e633b6c
--- /dev/null
+++ b/tests/android_car_api_test/src/android/car/apitest/TestDrivingSafetyRegionNoMetadataActivity.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 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.car.apitest;
+
+import android.app.Activity;
+
+public class TestDrivingSafetyRegionNoMetadataActivity extends Activity {
+}
diff --git a/tests/android_car_api_test/src/android/car/apitest/TestDrivingSafetyTwoRegionsActivity.java b/tests/android_car_api_test/src/android/car/apitest/TestDrivingSafetyTwoRegionsActivity.java
new file mode 100644
index 0000000..3124b81
--- /dev/null
+++ b/tests/android_car_api_test/src/android/car/apitest/TestDrivingSafetyTwoRegionsActivity.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2021 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.car.apitest;
+
+import android.app.Activity;
+
+public class TestDrivingSafetyTwoRegionsActivity extends Activity {
+}