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