1/* 2 * Copyright (C) 2013 DroidDriver committers 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 17package io.appium.droiddriver.helpers; 18 19import android.annotation.TargetApi; 20import android.app.Instrumentation; 21import android.os.Build; 22 23import io.appium.droiddriver.DroidDriver; 24import io.appium.droiddriver.exceptions.DroidDriverException; 25import io.appium.droiddriver.instrumentation.InstrumentationDriver; 26import io.appium.droiddriver.uiautomation.UiAutomationDriver; 27import io.appium.droiddriver.util.InstrumentationUtils; 28 29/** 30 * Static utility methods using a singleton {@link DroidDriver} instance. This class is NOT 31 * required, but it is handy and using a singleton driver can avoid memory leak when you have many 32 * instances around (for example, one in every test - JUnit framework keeps the test instances in 33 * memory after running them). 34 */ 35public class DroidDrivers { 36 private static DroidDriver driver; 37 38 /** 39 * Gets the singleton driver. Throws if {@link #setSingleton} has not been called. 40 */ 41 public static DroidDriver get() { 42 if (driver == null) { 43 throw new DroidDriverException("setSingleton() has not been called"); 44 } 45 return driver; 46 } 47 48 /** 49 * Sets the singleton driver. 50 */ 51 public static void setSingleton(DroidDriver driver) { 52 if (DroidDrivers.driver != null) { 53 throw new DroidDriverException("setSingleton() can only be called once"); 54 } 55 DroidDrivers.driver = driver; 56 } 57 58 /** 59 * Returns whether the running target (device or emulator) has {@link android.app.UiAutomation} 60 * API, which is introduced in SDK API 18 (JELLY_BEAN_MR2). 61 */ 62 public static boolean hasUiAutomation() { 63 return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2; 64 } 65 66 /** 67 * Returns a new DroidDriver instance. If am instrument options have "driver", treat it as the 68 * fully-qualified-class-name and create a new instance of it with {@code instrumentation} as the 69 * argument; otherwise a new platform-dependent default DroidDriver instance. 70 */ 71 public static DroidDriver newDriver() { 72 Instrumentation instrumentation = InstrumentationUtils.getInstrumentation(); 73 String driverClass = InstrumentationUtils.getD2Option("driver"); 74 if (driverClass != null) { 75 try { 76 return (DroidDriver) Class.forName(driverClass).getConstructor(Instrumentation.class) 77 .newInstance(instrumentation); 78 } catch (Throwable t) { 79 throw DroidDriverException.propagate(t); 80 } 81 } 82 83 // If "dd.driver" is not specified, return default. 84 if (hasUiAutomation()) { 85 checkUiAutomation(); 86 return new UiAutomationDriver(instrumentation); 87 } 88 return new InstrumentationDriver(instrumentation); 89 } 90 91 /** Checks if UiAutomation API is available */ 92 @TargetApi(18) 93 public static void checkUiAutomation() { 94 if (!hasUiAutomation()) { 95 throw new DroidDriverException("UiAutomation is not available below API 18. " 96 + "See http://developer.android.com/reference/android/app/UiAutomation.html"); 97 } 98 if (InstrumentationUtils.getInstrumentation().getUiAutomation() == null) { 99 throw new DroidDriverException( 100 "uiAutomation==null: did you forget to set '-w' flag for 'am instrument'?"); 101 } 102 } 103} 104