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 */ 16 17 package android.car.cts; 18 19 import static com.google.common.truth.Truth.assertWithMessage; 20 21 import android.app.UiAutomation; 22 import android.car.Car; 23 import android.car.FuelType; 24 import android.car.PortLocationType; 25 import android.car.test.AbstractExpectableTestCase; 26 import android.car.test.PermissionsCheckerRule; 27 import android.content.ComponentName; 28 import android.content.Context; 29 import android.content.ServiceConnection; 30 import android.os.IBinder; 31 import android.os.Looper; 32 import android.os.ParcelFileDescriptor; 33 import android.platform.test.flag.junit.CheckFlagsRule; 34 import android.platform.test.flag.junit.DeviceFlagsValueProvider; 35 36 import androidx.test.platform.app.InstrumentationRegistry; 37 38 import org.junit.After; 39 import org.junit.Before; 40 import org.junit.Rule; 41 42 import java.io.ByteArrayOutputStream; 43 import java.io.IOException; 44 import java.io.InputStream; 45 import java.util.Arrays; 46 import java.util.List; 47 import java.util.concurrent.Semaphore; 48 import java.util.concurrent.TimeUnit; 49 50 /** 51 * Base class for tests that don't need to connect to a {@link android.car.Car} object. 52 * 53 * <p>For tests that don't need a {@link android.car.Car} object, use 54 * {@link AbstractCarLessTestCase} instead. 55 */ 56 abstract class AbstractCarTestCase extends AbstractExpectableTestCase { 57 58 private static final String TAG = AbstractCarTestCase.class.getSimpleName(); 59 60 protected static final long DEFAULT_WAIT_TIMEOUT_MS = 1000; 61 62 // Enums in FuelType 63 protected static final List<Integer> EXPECTED_FUEL_TYPES = 64 Arrays.asList(FuelType.UNKNOWN, FuelType.UNLEADED, FuelType.LEADED, FuelType.DIESEL_1, 65 FuelType.DIESEL_2, FuelType.BIODIESEL, FuelType.E85, FuelType.LPG, FuelType.CNG, 66 FuelType.LNG, FuelType.ELECTRIC, FuelType.HYDROGEN, FuelType.OTHER); 67 // Enums in PortLocationType 68 protected static final List<Integer> EXPECTED_PORT_LOCATIONS = 69 Arrays.asList(PortLocationType.UNKNOWN, PortLocationType.FRONT_LEFT, 70 PortLocationType.FRONT_RIGHT, PortLocationType.REAR_RIGHT, 71 PortLocationType.REAR_LEFT, PortLocationType.FRONT, PortLocationType.REAR); 72 73 // CheckFlagsRule rule needs to before PermissionsCheckerRule. 74 @Rule(order = 0) 75 public final CheckFlagsRule checkFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); 76 77 @Rule(order = 1) 78 public final PermissionsCheckerRule permissionsCheckerRule = new PermissionsCheckerRule(); 79 80 protected final Context mContext = InstrumentationRegistry.getInstrumentation().getContext(); 81 82 private final DefaultServiceConnectionListener mConnectionListener = 83 new DefaultServiceConnectionListener(); 84 85 private Car mCar; 86 assertMainThread()87 protected void assertMainThread() { 88 assertWithMessage("Looper.getMainLooper().isCurrentThread()") 89 .that(Looper.getMainLooper().isCurrentThread()).isTrue(); 90 } 91 92 @Before createCar()93 public final void createCar() throws Exception { 94 mCar = Car.createCar(mContext); 95 } 96 97 @After disconnectCar()98 public final void disconnectCar() throws Exception { 99 if (mCar != null) { 100 mCar.disconnect(); 101 } 102 } 103 startUser(int userId)104 public void startUser(int userId) throws Exception { 105 executeShellCommand("am start-user %d", userId); 106 } 107 getCar()108 protected synchronized Car getCar() { 109 return mCar; 110 } 111 112 protected class DefaultServiceConnectionListener implements ServiceConnection { 113 private final Semaphore mConnectionWait = new Semaphore(0); 114 waitForConnection(long timeoutMs)115 public void waitForConnection(long timeoutMs) throws InterruptedException { 116 mConnectionWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS); 117 } 118 119 @Override onServiceDisconnected(ComponentName name)120 public void onServiceDisconnected(ComponentName name) { 121 assertMainThread(); 122 } 123 124 @Override onServiceConnected(ComponentName name, IBinder service)125 public void onServiceConnected(ComponentName name, IBinder service) { 126 assertMainThread(); 127 mConnectionWait.release(); 128 } 129 } 130 executeShellCommand(String commandFormat, Object... args)131 protected static String executeShellCommand(String commandFormat, Object... args) 132 throws IOException { 133 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 134 return executeShellCommand(uiAutomation, commandFormat, args); 135 } 136 executeShellCommandWithPermission(String permission, String commandFormat, Object... args)137 protected static String executeShellCommandWithPermission(String permission, 138 String commandFormat, Object... args) throws IOException { 139 UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation(); 140 String result; 141 try { 142 uiAutomation.adoptShellPermissionIdentity(permission); 143 result = executeShellCommand(uiAutomation, commandFormat, args); 144 } finally { 145 uiAutomation.dropShellPermissionIdentity(); 146 } 147 return result; 148 } 149 executeShellCommand(UiAutomation uiAutomation, String commandFormat, Object... args)150 private static String executeShellCommand(UiAutomation uiAutomation, String commandFormat, 151 Object... args) throws IOException { 152 ParcelFileDescriptor stdout = uiAutomation.executeShellCommand( 153 String.format(commandFormat, args)); 154 try (InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(stdout)) { 155 ByteArrayOutputStream result = new ByteArrayOutputStream(); 156 byte[] buffer = new byte[1024]; 157 int length; 158 while ((length = inputStream.read(buffer)) != -1) { 159 result.write(buffer, 0, length); 160 } 161 return result.toString("UTF-8"); 162 } 163 } 164 } 165