170e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin/* 270e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin * Copyright (C) 2013 DroidDriver committers 370e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin * 470e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin * Licensed under the Apache License, Version 2.0 (the "License"); 570e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin * you may not use this file except in compliance with the License. 670e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin * You may obtain a copy of the License at 770e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin * 870e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin * http://www.apache.org/licenses/LICENSE-2.0 970e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin * 1070e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin * Unless required by applicable law or agreed to in writing, software 1170e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin * distributed under the License is distributed on an "AS IS" BASIS, 1270e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1370e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin * See the License for the specific language governing permissions and 1470e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin * limitations under the License. 1570e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin */ 1670e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin 174b31201b5a2dbf8036da5a8d089a68a39cc1dc44Kevin Jinpackage io.appium.droiddriver.base; 1870e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin 1970e34108e0fc19277e642aef3b36b65b8e254899Kevin Jinimport android.app.Service; 20f50519233078e65a056cff49d7b4989d57c3e750Kevin Jinimport android.graphics.Bitmap; 21f50519233078e65a056cff49d7b4989d57c3e750Kevin Jinimport android.graphics.Bitmap.CompressFormat; 2270e34108e0fc19277e642aef3b36b65b8e254899Kevin Jinimport android.os.PowerManager; 23f50519233078e65a056cff49d7b4989d57c3e750Kevin Jinimport android.util.Log; 2470e34108e0fc19277e642aef3b36b65b8e254899Kevin Jinimport android.view.KeyEvent; 254b31201b5a2dbf8036da5a8d089a68a39cc1dc44Kevin Jinimport io.appium.droiddriver.UiDevice; 264b31201b5a2dbf8036da5a8d089a68a39cc1dc44Kevin Jinimport io.appium.droiddriver.actions.Action; 274b31201b5a2dbf8036da5a8d089a68a39cc1dc44Kevin Jinimport io.appium.droiddriver.actions.SingleKeyAction; 284b31201b5a2dbf8036da5a8d089a68a39cc1dc44Kevin Jinimport io.appium.droiddriver.util.FileUtils; 29b095ce8840ef1e78bb4a944cc888da368308105fkjinimport io.appium.droiddriver.util.InstrumentationUtils; 304b31201b5a2dbf8036da5a8d089a68a39cc1dc44Kevin Jinimport io.appium.droiddriver.util.Logs; 31b095ce8840ef1e78bb4a944cc888da368308105fkjinimport java.io.BufferedOutputStream; 324b31201b5a2dbf8036da5a8d089a68a39cc1dc44Kevin Jin 3370e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin/** 3470e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin * Base implementation of {@link UiDevice}. 3570e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin */ 36f50519233078e65a056cff49d7b4989d57c3e750Kevin Jinpublic abstract class BaseUiDevice implements UiDevice { 3770e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin // power off may not trigger new events 38337fafc3b2ede7dbd1be4d1ed0bbfdfdbbbd684bEric Fitchett private static final SingleKeyAction POWER_OFF = new SingleKeyAction(KeyEvent.KEYCODE_POWER, 39337fafc3b2ede7dbd1be4d1ed0bbfdfdbbbd684bEric Fitchett 0/* metaState */, 0/* timeoutMillis */, false); 4070e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin // power on should always trigger new events 41d414dc59622a9a8a0a2e3af94387d2ecd148ca55Kevin Jin private static final SingleKeyAction POWER_ON = new SingleKeyAction(KeyEvent.KEYCODE_POWER, 42337fafc3b2ede7dbd1be4d1ed0bbfdfdbbbd684bEric Fitchett 0/* metaState */, 1000L/* timeoutMillis */, false); 4370e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin 4485ac3efb066be44e93941edb24157c22a5a365deKevin Jin @SuppressWarnings("deprecation") 4570e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin @Override 4670e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin public boolean isScreenOn() { 4770e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin PowerManager pm = 48f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin (PowerManager) getContext().getInstrumentation().getTargetContext() 49f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin .getSystemService(Service.POWER_SERVICE); 5070e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin return pm.isScreenOn(); 5170e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin } 5270e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin 5370e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin @Override 5470e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin public void wakeUp() { 5570e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin if (!isScreenOn()) { 56b095ce8840ef1e78bb4a944cc888da368308105fkjin // Cannot call perform(POWER_ON) because perform() checks the UiElement is visible. 57b095ce8840ef1e78bb4a944cc888da368308105fkjin POWER_ON.perform(getContext().getDriver().getInjector(), null); 58b095ce8840ef1e78bb4a944cc888da368308105fkjin InstrumentationUtils.tryWaitForIdleSync(POWER_ON.getTimeoutMillis()); 59b095ce8840ef1e78bb4a944cc888da368308105fkjin 60b095ce8840ef1e78bb4a944cc888da368308105fkjin Logs.log( 61b095ce8840ef1e78bb4a944cc888da368308105fkjin Log.WARN, 62b095ce8840ef1e78bb4a944cc888da368308105fkjin "After wakeUp, root AccessibilityNodeInfo may not be available. This is seen" 63b095ce8840ef1e78bb4a944cc888da368308105fkjin + " on api 23 devices, but could also happen on earlier devices."); 6470e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin } 6570e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin } 6670e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin 6770e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin @Override 6870e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin public void sleep() { 6970e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin if (isScreenOn()) { 7070e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin perform(POWER_OFF); 7170e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin } 7270e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin } 7346cbd1ba6301e660d32bed661bd65994d4911c4eKevin Jin 7446cbd1ba6301e660d32bed661bd65994d4911c4eKevin Jin @Override 7546cbd1ba6301e660d32bed661bd65994d4911c4eKevin Jin public void pressBack() { 7646cbd1ba6301e660d32bed661bd65994d4911c4eKevin Jin perform(SingleKeyAction.BACK); 7746cbd1ba6301e660d32bed661bd65994d4911c4eKevin Jin } 7870e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin 7970e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin @Override 8070e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin public boolean perform(Action action) { 81f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin return getContext().getDriver().getRootElement().perform(action); 82f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin } 83f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin 84f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin @Override 85f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin public boolean takeScreenshot(String path) { 86f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin return takeScreenshot(path, Bitmap.CompressFormat.PNG, 0); 8770e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin } 88f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin 89f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin @Override 90f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin public boolean takeScreenshot(String path, CompressFormat format, int quality) { 91f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin Logs.call(this, "takeScreenshot", path, quality); 92f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin Bitmap screenshot = takeScreenshot(); 93f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin if (screenshot == null) { 94f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin return false; 95f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin } 96f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin BufferedOutputStream bos = null; 97f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin try { 98f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin bos = FileUtils.open(path); 99f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin screenshot.compress(format, quality, bos); 100f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin return true; 101f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin } catch (Exception e) { 102f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin Logs.log(Log.WARN, e); 103f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin return false; 104f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin } finally { 105f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin if (bos != null) { 106f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin try { 107f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin bos.close(); 108f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin } catch (Exception e) { 109f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin // ignore 110f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin } 111f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin } 112f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin screenshot.recycle(); 113f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin } 114f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin } 115f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin 116f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin protected abstract Bitmap takeScreenshot(); 117f50519233078e65a056cff49d7b4989d57c3e750Kevin Jin 11874676fdd3c8a9e599eddd13bea56898674d9916aKevin Jin protected abstract DroidDriverContext<?, ?> getContext(); 11970e34108e0fc19277e642aef3b36b65b8e254899Kevin Jin} 120