def session(self, pkg_name=None, attach=False, launch_timeout=None): """ Create a new session Args: pkg_name (str): android package name attach (bool): attach to already running app launch_timeout (int): launch timeout Raises: requests.HTTPError, SessionBrokenError """ if pkg_name is None: return self._default_session if not attach: request_data = {"flags": "-W -S"} if launch_timeout: request_data["timeout"] = str(launch_timeout) resp = self._reqsess.post(self.path2url("/session/" + pkg_name), data=request_data) if resp.status_code == 410: # Gone raise SessionBrokenError(pkg_name, resp.text) resp.raise_for_status() jsondata = resp.json() if not jsondata["success"]: raise SessionBrokenError("app launch failed", jsondata["error"], jsondata["output"]) time.sleep(2.5) # wait launch finished, maybe no need pid = self._pidof_app(pkg_name) if not pid: raise SessionBrokenError(pkg_name) return Session(self, pkg_name, pid)
def jsonrpc_call(self, jsonrpc_url, method, params=[], http_timeout=60): """ jsonrpc2 call Refs: - http://www.jsonrpc.org/specification """ request_start = time.time() data = { "jsonrpc": "2.0", "id": self._jsonrpc_id(method), "method": method, "params": params, } data = json.dumps(data).encode('utf-8') res = self._reqsess.post( jsonrpc_url, # +"?m="+method, #?method is for debug headers={"Content-Type": "application/json"}, timeout=http_timeout, data=data) if DEBUG: print("Shell$ curl -X POST -d '{}' {}".format(data, jsonrpc_url)) print("Output> " + res.text) if res.status_code == 502: raise GatewayError( res, "gateway error, time used %.1fs" % (time.time() - request_start)) if res.status_code == 410: # http status gone: session broken raise SessionBrokenError("app quit or crash", jsonrpc_url, res.text) if res.status_code != 200: raise UiaError(jsonrpc_url, data, res.status_code, res.text, "HTTP Return code is not 200", res.text) jsondata = res.json() error = jsondata.get('error') if not error: return jsondata.get('result') # error happends err = JsonRpcError(error, method) if isinstance( err.data, six.string_types) and 'UiAutomation not connected' in err.data: err.__class__ = UiAutomationNotConnectedError elif err.message: if 'uiautomator.UiObjectNotFoundException' in err.message: err.__class__ = UiObjectNotFoundError elif 'android.support.test.uiautomator.StaleObjectException' in err.message: # StaleObjectException # https://developer.android.com/reference/android/support/test/uiautomator/StaleObjectException.html # A StaleObjectException exception is thrown when a UiObject2 is used after the underlying View has been destroyed. # In this case, it is necessary to call findObject(BySelector) to obtain a new UiObject2 instance. err.__class__ = StaleObjectExceptionError elif 'java.lang.NullObjectException' in err.message: err.__class__ = NullObjectExceptionError elif 'java.lang.NullPointerException' == err.message: err.__class__ = NullPointerExceptionError raise err
def inner(self, *args, **kwargs): if not self.running(): raise SessionBrokenError(self._pkg_name) return fn(self, *args, **kwargs)
def app_start(self, pkg_name, activity=None, extras={}, wait=True, stop=False, unlock=False, launch_timeout=None, use_monkey=False): """ Launch application Args: pkg_name (str): package name activity (str): app activity stop (bool): Stop app before starting the activity. (require activity) use_monkey (bool): use monkey command to start app when activity is not given wait (bool): wait until app started. default True Raises: SessionBrokenError """ if unlock: self.unlock() if stop: self.app_stop(pkg_name) if activity: # -D: enable debugging # -W: wait for launch to complete # -S: force stop the target app before starting the activity # --user <USER_ID> | current: Specify which user to run as; if not # specified then run as the current user. # -e <EXTRA_KEY> <EXTRA_STRING_VALUE> # --ei <EXTRA_KEY> <EXTRA_INT_VALUE> # --ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> args = [ 'am', 'start', '-a', 'android.intent.action.MAIN', '-c', 'android.intent.category.LAUNCHER' ] if wait: args.append('-W') args += ['-n', '{}/{}'.format(pkg_name, activity)] # -e --ez extra_args = [] for k, v in extras.items(): if isinstance(v, bool): extra_args.extend(['--ez', k, 'true' if v else 'false']) elif isinstance(v, int): extra_args.extend(['--ei', k, str(v)]) else: extra_args.extend(['-e', k, v]) args += extra_args # 'am', 'start', '-W', '-n', '{}/{}'.format(pkg_name, activity)) self.shell(args) elif use_monkey: self.shell([ 'monkey', '-p', pkg_name, '-c', 'android.intent.category.LAUNCHER', '1' ]) else: # launch with atx-agent data = {"flags": "-W"} if launch_timeout: data["timeout"] = str(launch_timeout) resp = self._reqsess.post( self.path2url("/session/" + pkg_name), data=data) if resp.status_code != 200: # 410: Gone raise SessionBrokenError(pkg_name, resp.text) jsondata = resp.json() if not jsondata["success"]: raise SessionBrokenError(pkg_name, jsondata["error"], jsondata["output"])