1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package com.android.car.test; 17 18import android.app.Activity; 19import android.content.ComponentName; 20import android.content.Intent; 21import android.hardware.automotive.vehicle.V2_0.VehicleDrivingStatus; 22import android.hardware.automotive.vehicle.V2_0.VehiclePropValue; 23import android.hardware.automotive.vehicle.V2_0.VehicleProperty; 24import android.hardware.automotive.vehicle.V2_0.VehiclePropertyAccess; 25import android.os.SystemClock; 26 27import com.android.car.SystemActivityMonitoringService; 28import com.android.car.SystemActivityMonitoringService.TopTaskInfoContainer; 29import com.android.car.vehiclehal.VehiclePropValueBuilder; 30import com.android.car.vehiclehal.test.MockedVehicleHal.VehicleHalPropertyHandler; 31 32import java.util.ArrayList; 33import java.util.List; 34import java.util.concurrent.Semaphore; 35import java.util.concurrent.TimeUnit; 36 37public class SystemActivityMonitoringServiceTest extends MockedCarTestBase { 38 private static final long TIMEOUT_MS = 3000; 39 private static final long POLL_INTERVAL_MS = 50; 40 private static final Semaphore sAvailable = new Semaphore(0); 41 42 private final DrivingStatusHandler mDrivingStatusHandler = new DrivingStatusHandler(); 43 44 @Override 45 protected synchronized void configureMockedHal() { 46 addProperty(VehicleProperty.DRIVING_STATUS, mDrivingStatusHandler) 47 .setAccess(VehiclePropertyAccess.READ); 48 } 49 50 private void init(boolean drivingStatusRestricted) { 51 // Set no restriction to driving status, to avoid CarPackageManagerService to launch a 52 // blocking activity. 53 mDrivingStatusHandler.setDrivingStatusRestricted(drivingStatusRestricted); 54 55 VehiclePropValue injectValue = 56 VehiclePropValueBuilder.newBuilder(VehicleProperty.DRIVING_STATUS) 57 .setTimestamp(SystemClock.elapsedRealtimeNanos()) 58 .addIntValue(0) 59 .build(); 60 getMockedVehicleHal().injectEvent(injectValue); 61 } 62 63 public void testActivityLaunch() { 64 init(false); 65 List<TopTaskInfoContainer> taskList = new ArrayList<>(); 66 SystemActivityMonitoringService systemActivityMonitoringService = 67 new SystemActivityMonitoringService(getContext()); 68 systemActivityMonitoringService.registerActivityLaunchListener( 69 new SystemActivityMonitoringService.ActivityLaunchListener() { 70 @Override 71 public void onActivityLaunch( 72 SystemActivityMonitoringService.TopTaskInfoContainer topTask) { 73 taskList.add(topTask); 74 } 75 }); 76 getContext().startActivity(new Intent(getContext(), ActivityA.class)); 77 verifyTopActivityPolling(taskList, 0, new ComponentName(getContext().getPackageName(), 78 ActivityA.class.getName())); 79 sAvailable.release(); 80 81 verifyTopActivityPolling(taskList, 1, new ComponentName(getContext().getPackageName(), 82 ActivityB.class.getName())); 83 sAvailable.release(); 84 85 verifyTopActivityPolling(taskList, 2, new ComponentName(getContext().getPackageName(), 86 ActivityC.class.getName())); 87 } 88 89 public void testActivityBlocking() { 90 init(false); 91 Semaphore blocked = new Semaphore(0); 92 List<TopTaskInfoContainer> taskList = new ArrayList<>(); 93 SystemActivityMonitoringService systemActivityMonitoringService = 94 new SystemActivityMonitoringService(getContext()); 95 96 ComponentName blackListedActivity = new ComponentName(getContext().getPackageName(), 97 ActivityC.class.getName()); 98 ComponentName blockingActivity = new ComponentName(getContext().getPackageName(), 99 BlockingActivity.class.getName()); 100 Intent newActivityIntent = new Intent(); 101 newActivityIntent.setComponent(blockingActivity); 102 103 systemActivityMonitoringService.registerActivityLaunchListener( 104 new SystemActivityMonitoringService.ActivityLaunchListener() { 105 @Override 106 public void onActivityLaunch( 107 SystemActivityMonitoringService.TopTaskInfoContainer topTask) { 108 taskList.add(topTask); 109 if (topTask.topActivity.equals(blackListedActivity)) { 110 systemActivityMonitoringService.blockActivity(topTask, 111 newActivityIntent); 112 blocked.release(); 113 } 114 } 115 }); 116 // start a black listed activity 117 getContext().startActivity(new Intent(getContext(), ActivityC.class)); 118 // wait for the listener to call blockActivity() 119 try { 120 blocked.tryAcquire(2, TimeUnit.SECONDS); 121 } catch (InterruptedException e) { 122 fail(e.getMessage()); 123 } 124 // We should first receive the blackListedActivity launch, 125 // and later the blockActivity launch 126 verifyTopActivityPolling(taskList, 0, blackListedActivity); 127 verifyTopActivityPolling(taskList, 1, blockingActivity); 128 } 129 130 private void verifyTopActivityPolling( 131 List<TopTaskInfoContainer> topTaskList, int i, ComponentName activity) { 132 boolean activityVerified = false; 133 int timeElapsedMs = 0; 134 try { 135 while (!activityVerified && timeElapsedMs <= TIMEOUT_MS) { 136 Thread.sleep(POLL_INTERVAL_MS); 137 timeElapsedMs += POLL_INTERVAL_MS; 138 if (topTaskList.size() <= i) continue; 139 TopTaskInfoContainer topTask = topTaskList.get(i); 140 if (topTask != null && topTask.topActivity.equals(activity)) { 141 activityVerified = true; 142 break; 143 } 144 } 145 assertEquals(true, activityVerified); 146 } catch (Exception e) { 147 fail(e.toString()); 148 } 149 } 150 151 public static class ActivityA extends Activity { 152 @Override 153 protected void onPostResume() { 154 super.onPostResume(); 155 // Wait until the activity launch event is consumed by the listener. 156 try { 157 if (!sAvailable.tryAcquire(2, TimeUnit.SECONDS)) { 158 fail("Time out"); 159 } 160 } catch (Exception e) { 161 fail(e.toString()); 162 } 163 Intent intent = new Intent(this, ActivityB.class); 164 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 165 startActivity(intent); 166 } 167 } 168 169 public static class ActivityB extends Activity { 170 @Override 171 protected void onPostResume() { 172 super.onPostResume(); 173 // Wait until the activity launch event is consumed by the listener. 174 try { 175 if (!sAvailable.tryAcquire(2, TimeUnit.SECONDS)) { 176 fail("Time out"); 177 } 178 } catch (Exception e) { 179 fail(e.toString()); 180 } 181 Intent intent = new Intent(this, ActivityC.class); 182 startActivity(intent); 183 } 184 } 185 186 public static class ActivityC extends Activity { 187 } 188 189 public static class BlockingActivity extends Activity { 190 } 191 192 private class DrivingStatusHandler implements VehicleHalPropertyHandler { 193 int mDrivingStatus = VehicleDrivingStatus.UNRESTRICTED; 194 195 public void setDrivingStatusRestricted(boolean restricted) { 196 mDrivingStatus = restricted ? VehicleDrivingStatus.NO_VIDEO 197 : VehicleDrivingStatus.UNRESTRICTED; 198 } 199 200 @Override 201 public void onPropertySet(VehiclePropValue value) { 202 } 203 204 @Override 205 public VehiclePropValue onPropertyGet(VehiclePropValue value) { 206 return VehiclePropValueBuilder.newBuilder(VehicleProperty.DRIVING_STATUS) 207 .setTimestamp(SystemClock.elapsedRealtimeNanos()) 208 .addIntValue(mDrivingStatus) 209 .build(); 210 } 211 212 @Override 213 public void onPropertySubscribe(int property, int zones, float sampleRate) { 214 } 215 216 @Override 217 public void onPropertyUnsubscribe(int property) { 218 } 219 } 220}