def __init__(self, device, picPath):
     super(UpdateScreen, self).__init__()
     self.isStop = False
     self._device = device
     self.delay = 0
     self.picPath = picPath
     self.lastFrameTime = 0
     self.isRefresh = False
     self.nconcurrent = threading.BoundedSemaphore(5)
     self.miniServer = MiniServer(self._device)
     self.miniReader = MiniReader(self._device)
 def __init__(self, device, picPath):
     super(UpdateScreen, self).__init__()
     self.isStop = False
     self._device = device
     self.delay = 0
     self.picPath = picPath
     self.lastFrameTime = 0
     self.isRefresh = False
     self.nconcurrent = threading.BoundedSemaphore(5)
     self.miniServer = MiniServer(self._device)
     self.miniReader = MiniReader(self._device)
class RunTest(QtCore.QThread):
    """
    Handle the reproduced actions and send back to device
    """
    actionResult = State.FAIL
    isStopRun = False
    limit = 0
    picData = None
    picImage = QtGui.QImage()
    finish = QtCore.Signal()
    currentAction = QtCore.Signal(AutoSenseItem)
    actionDone = QtCore.Signal(AutoSenseItem, int, int)

    def __init__(self, times=1, device=None):
        super(RunTest, self).__init__()
        self.setTimes(times)
        self.setDevice(device)
        self.setMinicap()
        self.actionSwitcher = {
            'Power': self.actionPower,
            'Unlock': self.actionUnlock,
            'Back': self.actionBack,
            'Click': self.actionClick,
            'Home': self.actionHome,
            'Swipe': self.actionSwipe,
            'Drag': self.actionDrag,
            'LongClick': self.actionLongClick,
            'Delay': self.actionDelay,
            'Menu': self.actionMenu,
            'Exist': self.actionCheckExist,
            'NoExist': self.actionCheckNoExist,
            'IsBlank': self.actionCheckBlank,
            'RelativeCheck': self.actionRelativeCheck,
            'Type': self.actionType,
            'MediaCheck': self.actionMediaCheck,
            'HideKeyboard': self.actionHideKeyboard,
            'CheckPoint': self.actionCheckPoint
        }

    def setMinicap(self):
        self.miniReader = MiniReader(self._device)
        self.miniServer = MiniServer(self._device)

    def setTimes(self, times):
        """
        Set repeat times of running a script. It should set before running.
        :param times: Set by user.
        """
        self.times = times

    def setActions(self, actions):
        """
        Assign actions that want to play.
        :param actions: List of AutoSense item.
        """
        self.actions = actions

    def setDevice(self, device):
        """
        Assign a instance of device.
        :param device: AdbDevice
        """
        self._device = device

    def setPlayName(self, name):
        self.playName = name

    def checkMedia(self, passTime, timeout, isHold):
        decryptRE = re.compile(
            '[lL]ast\s+write\s+occurred\s+\(msecs\):\s+(?P<last_write>\d+)')
        current_sec_time = lambda: time.time()
        isAlreadyPass = False
        idle = current_sec_time()
        work = idle
        hold = True if isHold == 'True' else False

        while not self.isStopRun:
            output = self._device.cmd.dumpsys(['media.audio_flinger'])
            decryptMatch = decryptRE.search(output)
            if decryptMatch is not None:
                lastWriteTime = int(decryptMatch.group('last_write'))
                if lastWriteTime < 1000:
                    idle = current_sec_time()
                    playTime = current_sec_time() - work
                    print 'play time = ' + str(
                        playTime) + '   passTime: ' + str(passTime)
                    if playTime > passTime:
                        if hold:
                            isAlreadyPass = True
                            timeout = 2
                        else:
                            return {'result': True, 'reason': ''}
                else:
                    work = current_sec_time()
                    idleTime = current_sec_time() - idle
                    print 'idleTime = ' + str(
                        idleTime) + ', idleTime > timeout: ' + str(
                            idleTime > timeout)
                    if idleTime > timeout:
                        if isAlreadyPass:
                            return {'result': True, 'reason': ''}
                        else:
                            return {'result': False, 'reason': 'timeout'}
            else:
                print 'It can\'t figure out last write time.'
                return {
                    'result': False,
                    'reason': 'Program can\'t define whether media is playing.'
                }
            time.sleep(0.1)

    def actionMediaCheck(self, param, refer=None):
        t, timeout, isHold = param
        result = self.checkMedia(int(t), int(timeout), isHold)
        if result is not None:
            if result['result']:
                self.actionResult = State.PASS

    def actionRelativeCheck(self, param, refer=None):
        pass

    def actionCheckPoint(self, param, refer=None):
        self.actionResult = State.SEMI

    def actionType(self, param, refer=None):
        """
        Action of typing text.
        :param param: a string
        :param refer: None
        """
        self._device.type(param[0])
        self.actionResult = State.PASS

    def actionDelay(self, param, refer=None):
        """

        :param param: (int). in second.
        :param refer: None
        """
        t = int(param[0])
        D_value = 0
        container = []
        startTime = float(
            self._device.cmd.shell(['echo', '$EPOCHREALTIME'], output=True))
        while not self.isStopRun and D_value < t:
            currentTime = float(
                self._device.cmd.shell(['echo', '$EPOCHREALTIME'],
                                       output=True))
            D_value = currentTime - startTime
            self.removeLastLog.emit()
            container.append(D_value)
            if len(container) > 1:
                if not self._device.isScreenOn():
                    self._device.powerBtn()
                    if self._device.isLocked():
                        self._device.unlock()
                del container[:]
            time.sleep(1)
        self.actionResult = State.PASS

    def actionUnlock(self, param, refer=None):
        """
        Unlock screen. If screen is not locked, it will do nothing.
        :param param: None
        :param refer: None
        """
        self._device.unlock()
        self.actionResult = State.PASS

    def actionMenu(self, param, refer=None):
        """
        Simulate menu button is pressed.
        :param param: None
        :param refer: None
        """
        self._device.cmd.inputKeyevnt('MENU')
        self.actionResult = State.PASS

    def actionPower(self, param, refer=None):
        """
        Simulate power button is pressed.
        :param param: None
        :param refer: None
        """
        self._device.cmd.inputKeyevnt('POWER')
        self.actionResult = State.PASS

    def actionHome(self, param, refer=None):
        """
        Simulate home button is pressed.
        :param param: None
        :param refer: None
        """
        self._device.cmd.inputKeyevnt('HOME')
        self.actionResult = State.PASS

    def actionLongClick(self, param, refer=None):
        """
        Simulate long click.
        :param param: [x, y, duration]
        :param refer: A json object include view information.
        """
        info = json.loads(refer)
        x, y, duration = param
        point = (int(x), int(y))
        self._device.longClick(point[0], point[1], int(duration))
        self.actionResult = State.PASS

    def actionDrag(self, param, refer=None):
        """
        Simulate drag action. It can drag a view object if it can be dragged.
        :param param: [x1, y1, x2, y2, duration]
        :param refer: None
        """
        start = (param[0], param[1])
        end = (param[2], param[3])
        self._device.drag(start, end, int(param[4]))
        self.actionResult = State.PASS

    def actionSwipe(self, param, refer=None):
        """
        Simulate swipe action. View won't be dragged
        :param param: [x1, y1, x2, y2, duration]
        :param refer: None
        """
        start = (param[0], param[1])
        end = (param[2], param[3])
        # ensure page flow
        self._device.swipe(start, end, int(param[4]))
        self.actionResult = State.PASS

    def actionBack(self, param, refer=None):
        """
        Simulate back button.
        :param param: None
        :param refer: None
        """
        self._device.backBtn()
        self.actionResult = State.PASS

    def actionClick(self, param, refer=None):
        """
        Simulate click action.
        :param param: [x, y]
        :param refer: A json object include view information.
        """
        info = json.loads(refer)
        if len(param) == 2:
            x, y = param
        else:
            x, y, _ = param

        point = (int(x), int(y))
        noShow = False
        wait = 5
        while self._device.isConnected() and not self.isStopRun and wait > 0:
            try:
                if not self._device.isScreenOn():
                    self._device.powerBtn()
                    if self._device.isLocked():
                        self._device.unlock()
                result = self._device.checkSamePoint(point, info)
                print 'reason = ' + result['reason']
                if result['answer']:
                    self.actionResult = State.PASS
                    break
                elif not noShow:
                    print 'wait view'
                time.sleep(1)
                wait -= 1
            except uiautomator.JsonRPCError as m:
                print 'JsonRPCError: ' + m.message
                break

    def actionCheckBlank(self, param, refer=None):
        """
        Check the target view should not have any child view.
        :param param: [Identification, x, y]. There are 4 kinds of identification(resourceId, text, description, className).
        :param refer: None
        """
        benchmark, x, y = param
        attribute, value = benchmark.split('=')
        point = (int(x), int(y))
        if attribute == 'text':
            selector = self._device.retrieveSelector(
                point, self._device.d(text=value))
            if selector:
                if selector.childCount == 0:
                    self.actionResult = State.PASS
            else:
                self.actionResult = State.PASS

        elif attribute == 'description':
            selector = self._device.retrieveSelector(
                point, self._device.d(description=value))
            if selector:
                if selector.childCount == 0:
                    self.actionResult = State.PASS
            else:
                self.actionResult = State.PASS

        elif attribute == 'resourceId':
            selector = self._device.retrieveSelector(
                point, self._device.d(resourceId=value))
            if selector:
                if selector.childCount == 0:
                    self.actionResult = State.PASS
            else:
                self.actionResult = State.PASS

        elif attribute == 'className':
            selector = self._device.retrieveSelector(
                point, self._device.d(className=value))
            if selector:
                if selector.childCount == 0:
                    self.actionResult = State.PASS
            else:
                self.actionResult = State.PASS

    def actionCheckExist(self, param, refer=None):
        """
        Check the target view whether is existed on the screen.
        :param param: [Identification, x, y]. There are 4 kinds of identification(resourceId, text, description, className).
        :param refer: None
        """
        benchmark, x, y = param
        attribute, value = benchmark.split('=')
        point = (int(x), int(y))
        if attribute == 'text':
            if self._device.retrieveSelector(point,
                                             self._device.d(text=value)):
                self.actionResult = State.PASS
                # self.report.emit(INFO, 'Pass: View exist', True)
            else:
                pass
                # self.report.emit(ERROR, 'Fail: View not exist', True)
                # self.isStopRun = True
        elif attribute == 'description':
            if self._device.retrieveSelector(
                    point, self._device.d(description=value)):
                self.actionResult = State.PASS
                # self.report.emit(INFO, 'Pass: View exist', True)
            else:
                pass
                # self.report.emit(ERROR, 'Fail: View not exist', True)
                # self.isStopRun = True
        elif attribute == 'resourceId':
            if self._device.retrieveSelector(point,
                                             self._device.d(resourceId=value)):
                self.actionResult = State.PASS
                # self.report.emit(INFO, 'Pass: View exist', True)
            else:
                pass
                # self.report.emit(ERROR, 'Fail: View not exist', True)
                # self.isStopRun = True
        elif attribute == 'className':
            if self._device.retrieveSelector(point,
                                             self._device.d(className=value)):
                self.actionResult = State.PASS
                # self.report.emit(INFO, 'Pass: View exist', True)
            else:
                pass
                # self.report.emit(ERROR, 'Fail: View not exist', True)
                # self.isStopRun = True

    def actionCheckNoExist(self, param, refer=None):
        """
        Check the target view whether isn't existed on the screen.
        :param param: [Identification, x, y]. There are 4 kinds of identification(resourceId, text, description, className).
        :param refer: None
        """
        benchmark, x, y = param
        attribute, value = benchmark.split('=')
        point = (int(x), int(y))
        if attribute == 'text':
            if not self._device.retrieveSelector(point,
                                                 self._device.d(text=value)):
                self.actionResult = State.PASS

        elif attribute == 'description':
            if not self._device.retrieveSelector(
                    point, self._device.d(description=value)):
                self.actionResult = State.PASS

        elif attribute == 'resourceId':
            if not self._device.retrieveSelector(
                    point, self._device.d(resourceId=value)):
                self.actionResult = State.PASS

        elif attribute == 'className':
            if not self._device.retrieveSelector(
                    point, self._device.d(className=value)):
                self.actionResult = State.PASS

    def actionHideKeyboard(self, param, refer=None):
        """
        Hide soft keyboard. If keyboard isn't showed, it will do nothing.
        :param param: None
        :param refer: None
        """
        self._device.hideKeyboard()
        self.actionResult = State.PASS

    def stop(self):
        """
        Exit this process.
        """
        self.isStopRun = True

    def setStartIndex(self, index):
        """
        chose a start index of actions.
        :param index: integer
        """
        self.startIndex = index

    def takeScreenShot(self, path):
        self.picData = self.miniReader.getDisplay()
        self.picImage.loadFromData(self.picData)
        self.picImage.save(path, 'JPEG')

    def run(self):
        self.isStopRun = False
        self.limit = 0
        try:
            self.miniServer.start()
            ''' wait for active '''
            while not self.miniServer.isActive():
                time.sleep(0.5)
            self.takeScreenShot(Global.IMAGE_FOLDER + '/%s_%d.jpg' %
                                (self.playName, 0))
            while self.limit < self.times and not self.isStopRun:
                self.limit += 1
                for index in range(len(self.actions)):
                    if not self.isStopRun and self.startIndex <= index:
                        self.index = index + 1
                        item = self.actions[index]
                        if self._device.isConnected():
                            self.actionResult = State.FAIL
                            self.currentAction.emit(item)
                            self.actionSwitcher.get(item.action())(
                                item.parameter(), item.information())
                            self.actionDone.emit(item, self.actionResult,
                                                 index)
                            self.takeScreenShot(Global.IMAGE_FOLDER +
                                                '/%s_%d.jpg' %
                                                (self.playName, self.index))
                            time.sleep(0.5)

                        else:
                            self.isStopRun = True
                            break
        except socket.error:
            print 'socket.error: device offline'
            self.isStopRun = True
        except ValueError as e:
            print 'ValueError: ' + e.message
            self.isStopRun = True
        except CalledProcessError, exc:
            print 'CalledProcessError: ' + str(exc)
            self.isStopRun = True
        finally:
class UpdateScreen(QtCore.QThread):
    """
    Keep capturing screen in the background.
    """
    loadDone = QtCore.Signal()
    startLoad = QtCore.Signal()
    deviceOffline = QtCore.Signal()
    isStop = False
    isPause = False

    def __init__(self, device, picPath):
        super(UpdateScreen, self).__init__()
        self.isStop = False
        self._device = device
        self.delay = 0
        self.picPath = picPath
        self.lastFrameTime = 0
        self.isRefresh = False
        self.nconcurrent = threading.BoundedSemaphore(5)
        self.miniServer = MiniServer(self._device)
        self.miniReader = MiniReader(self._device)

    def stop(self):
        """ Stop capturing """
        self.isStop = True
        self.miniServer.stop()

    # def pause(self):
    #     """ Pause capturing """
    #     self.isPause = True
    #     self.miniServer.stop()
    #
    # def resume(self):
    #     """ resume capturing """
    #     self.isPause = False
    #     # self.start()

    def setDelay(self, delay=0):
        """ Set a delay time to start capturing """
        self.delay = delay

    def run(self):
        time.sleep(self.delay)
        try:
            self.miniServer.start()
            self.isStop = False
            while not self.isStop:
                if self.miniServer.isActive():
                    if not self.miniServer.needRestart():
                        self.startLoad.emit()
                        self.screenshot(path=self.picPath + '/' +
                                        self._device.serialno + '_screen.jpg')
                    else:
                        self.miniServer.reStart()
                else:
                    time.sleep(0.5)
                    # self.isPause = True
        except:
            print 'device not found'
            self.lastFrameTime = 0
            self.deviceOffline.emit()
        finally:
            self.miniServer.stop()

    def monitorFrame(self):
        """
        monitor the screen has changed, it helps to reduce capturing frequency.
        """
        decryptRE = re.compile('\s+events-delivered:\s+(?P<number>\d+)')
        output = self._device.cmd.dumpsys(['SurfaceFlinger'])
        if output:
            m = decryptRE.search(output)
            if m is not None:
                tmpTime = m.group('number')
                if tmpTime != self.lastFrameTime:
                    self.lastFrameTime = tmpTime
                    return True

    def screenshot(self, path, delay=0):
        """
        Do screen capture
        :param path: save pic path
        :param delay: delay to capture screen. In second.
        """
        try:
            # self.nconcurrent.acquire()
            time.sleep(delay)
            pp = time.time()
            if self._device.isConnected():
                if self.miniServer.isActive():
                    byteData = self.miniReader.getDisplay()
                    im = QtGui.QImage.fromData(
                        QtCore.QByteArray.fromRawData(byteData))
                    im.loadFromData(byteData)
                    im.save(path, 'JPEG')
            else:
                if not self.isStop:
                    self.deviceOffline.emit()
            print time.time() - pp
            if not self.isStop:
                self.loadDone.emit()
        except AttributeError as e:
            print e.message
        except IOError as e:
            print e.message
        # finally:
        #     self.nconcurrent.release()

    def __byteToHex(self, bs):
        return ''.join(['%02X ' % ord(byte) for byte in bs])

    def __parsePicSize(self, data):
        return int(binascii.hexlify(data[::-1]), 16)

    def __parseBanner(self, data):
        if len(data) == 24:
            banner = dict()
            banner['version'] = int(binascii.hexlify(data[0]), 16)
            banner['length'] = int(binascii.hexlify(data[1]), 16)
            banner['pid'] = int(binascii.hexlify(data[2:5][::-1]), 16)
            banner['real.width'] = int(binascii.hexlify(data[6:9][::-1]), 16)
            banner['real.height'] = int(binascii.hexlify(data[10:13][::-1]),
                                        16)
            banner['virtual.width'] = int(binascii.hexlify(data[14:17][::-1]),
                                          16)
            banner['virtual.height'] = int(binascii.hexlify(data[18:21][::-1]),
                                           16)
            banner['orient'] = int(binascii.hexlify(data[22]), 16)
            banner['policy'] = int(binascii.hexlify(data[23]), 16)
            return banner
 def setMinicap(self):
     self.miniReader = MiniReader(self._device)
     self.miniServer = MiniServer(self._device)
class RunTest(QtCore.QThread):
    """
    Handle the reproduced actions and send back to device
    """
    actionResult = State.FAIL
    isStopRun = False
    limit = 0
    picData = None
    picImage = QtGui.QImage()
    finish = QtCore.Signal()
    currentAction = QtCore.Signal(AutoSenseItem)
    actionDone = QtCore.Signal(AutoSenseItem, int, int)

    def __init__(self, times=1, device=None):
        super(RunTest, self).__init__()
        self.setTimes(times)
        self.setDevice(device)
        self.setMinicap()
        self.actionSwitcher = {
            'Power': self.actionPower,
            'Unlock': self.actionUnlock,
            'Back': self.actionBack,
            'Click': self.actionClick,
            'Home': self.actionHome,
            'Swipe': self.actionSwipe,
            'Drag': self.actionDrag,
            'LongClick': self.actionLongClick,
            'Delay': self.actionDelay,
            'Menu': self.actionMenu,
            'Exist': self.actionCheckExist,
            'NoExist': self.actionCheckNoExist,
            'IsBlank': self.actionCheckBlank,
            'RelativeCheck': self.actionRelativeCheck,
            'Type': self.actionType,
            'MediaCheck': self.actionMediaCheck,
            'HideKeyboard': self.actionHideKeyboard,
            'CheckPoint': self.actionCheckPoint}

    def setMinicap(self):
        self.miniReader = MiniReader(self._device)
        self.miniServer = MiniServer(self._device)

    def setTimes(self, times):
        """
        Set repeat times of running a script. It should set before running.
        :param times: Set by user.
        """
        self.times = times

    def setActions(self, actions):
        """
        Assign actions that want to play.
        :param actions: List of AutoSense item.
        """
        self.actions = actions

    def setDevice(self, device):
        """
        Assign a instance of device.
        :param device: AdbDevice
        """
        self._device = device

    def setPlayName(self, name):
        self.playName = name

    def checkMedia(self, passTime, timeout, isHold):
        decryptRE = re.compile('[lL]ast\s+write\s+occurred\s+\(msecs\):\s+(?P<last_write>\d+)')
        current_sec_time = lambda: time.time()
        isAlreadyPass = False
        idle = current_sec_time()
        work = idle
        hold = True if isHold == 'True' else False

        while not self.isStopRun:
            output = self._device.cmd.dumpsys(['media.audio_flinger'])
            decryptMatch = decryptRE.search(output)
            if decryptMatch is not None:
                lastWriteTime = int(decryptMatch.group('last_write'))
                if lastWriteTime < 1000:
                    idle = current_sec_time()
                    playTime = current_sec_time() - work
                    print 'play time = ' + str(playTime) + '   passTime: ' + str(passTime)
                    if playTime > passTime:
                        if hold:
                            isAlreadyPass = True
                            timeout = 2
                        else:
                            return {'result': True, 'reason': ''}
                else:
                    work = current_sec_time()
                    idleTime = current_sec_time() - idle
                    print 'idleTime = ' + str(idleTime) + ', idleTime > timeout: ' + str(idleTime > timeout)
                    if idleTime > timeout:
                        if isAlreadyPass:
                            return {'result': True, 'reason': ''}
                        else:
                            return {'result': False, 'reason': 'timeout'}
            else:
                print 'It can\'t figure out last write time.'
                return {'result': False, 'reason': 'Program can\'t define whether media is playing.'}
            time.sleep(0.1)

    def actionMediaCheck(self, param, refer=None):
        t, timeout, isHold = param
        result = self.checkMedia(int(t), int(timeout), isHold)
        if result is not None:
            if result['result']:
                self.actionResult = State.PASS

    def actionRelativeCheck(self, param, refer=None):
        pass

    def actionCheckPoint(self, param, refer=None):
        self.actionResult = State.SEMI

    def actionType(self, param, refer=None):
        """
        Action of typing text.
        :param param: a string
        :param refer: None
        """
        self._device.type(param[0])
        self.actionResult = State.PASS

    def actionDelay(self, param, refer=None):
        """

        :param param: (int). in second.
        :param refer: None
        """
        t = int(param[0])
        D_value = 0
        container = []
        startTime = float(self._device.cmd.shell(['echo', '$EPOCHREALTIME'], output=True))
        while not self.isStopRun and D_value < t:
            currentTime = float(self._device.cmd.shell(['echo', '$EPOCHREALTIME'], output=True))
            D_value = currentTime - startTime
            self.removeLastLog.emit()
            container.append(D_value)
            if len(container) > 1:
                if not self._device.isScreenOn():
                    self._device.powerBtn()
                    if self._device.isLocked():
                        self._device.unlock()
                del container[:]
            time.sleep(1)
        self.actionResult = State.PASS

    def actionUnlock(self, param, refer=None):
        """
        Unlock screen. If screen is not locked, it will do nothing.
        :param param: None
        :param refer: None
        """
        self._device.unlock()
        self.actionResult = State.PASS

    def actionMenu(self, param, refer=None):
        """
        Simulate menu button is pressed.
        :param param: None
        :param refer: None
        """
        self._device.cmd.inputKeyevnt('MENU')
        self.actionResult = State.PASS

    def actionPower(self, param, refer=None):
        """
        Simulate power button is pressed.
        :param param: None
        :param refer: None
        """
        self._device.cmd.inputKeyevnt('POWER')
        self.actionResult = State.PASS

    def actionHome(self, param, refer=None):
        """
        Simulate home button is pressed.
        :param param: None
        :param refer: None
        """
        self._device.cmd.inputKeyevnt('HOME')
        self.actionResult = State.PASS

    def actionLongClick(self, param, refer=None):
        """
        Simulate long click.
        :param param: [x, y, duration]
        :param refer: A json object include view information.
        """
        info = json.loads(refer)
        x, y, duration = param
        point = (int(x), int(y))
        self._device.longClick(point[0], point[1], int(duration))
        self.actionResult = State.PASS

    def actionDrag(self, param, refer=None):
        """
        Simulate drag action. It can drag a view object if it can be dragged.
        :param param: [x1, y1, x2, y2, duration]
        :param refer: None
        """
        start = (param[0], param[1])
        end = (param[2], param[3])
        self._device.drag(start, end, int(param[4]))
        self.actionResult = State.PASS

    def actionSwipe(self, param, refer=None):
        """
        Simulate swipe action. View won't be dragged
        :param param: [x1, y1, x2, y2, duration]
        :param refer: None
        """
        start = (param[0], param[1])
        end = (param[2], param[3])
        # ensure page flow
        self._device.swipe(start, end, int(param[4]))
        self.actionResult = State.PASS

    def actionBack(self, param, refer=None):
        """
        Simulate back button.
        :param param: None
        :param refer: None
        """
        self._device.backBtn()
        self.actionResult = State.PASS

    def actionClick(self, param, refer=None):
        """
        Simulate click action.
        :param param: [x, y]
        :param refer: A json object include view information.
        """
        info = json.loads(refer)
        if len(param) == 2:
            x, y = param
        else:
            x, y, _ = param

        point = (int(x), int(y))
        noShow = False
        wait = 5
        while self._device.isConnected() and not self.isStopRun and wait > 0:
            try:
                if not self._device.isScreenOn():
                    self._device.powerBtn()
                    if self._device.isLocked():
                        self._device.unlock()
                result = self._device.checkSamePoint(point, info)
                print 'reason = '+result['reason']
                if result['answer']:
                    self.actionResult = State.PASS
                    break
                elif not noShow:
                    print 'wait view'
                time.sleep(1)
                wait -= 1
            except uiautomator.JsonRPCError as m:
                print 'JsonRPCError: ' + m.message
                break

    def actionCheckBlank(self, param, refer=None):
        """
        Check the target view should not have any child view.
        :param param: [Identification, x, y]. There are 4 kinds of identification(resourceId, text, description, className).
        :param refer: None
        """
        benchmark, x, y = param
        attribute, value = benchmark.split('=')
        point = (int(x), int(y))
        if attribute == 'text':
            selector = self._device.retrieveSelector(point, self._device.d(text=value))
            if selector:
                if selector.childCount == 0:
                    self.actionResult = State.PASS
            else:
                self.actionResult = State.PASS

        elif attribute == 'description':
            selector = self._device.retrieveSelector(point, self._device.d(description=value))
            if selector:
                if selector.childCount == 0:
                    self.actionResult = State.PASS
            else:
                self.actionResult = State.PASS

        elif attribute == 'resourceId':
            selector = self._device.retrieveSelector(point, self._device.d(resourceId=value))
            if selector:
                if selector.childCount == 0:
                    self.actionResult = State.PASS
            else:
                self.actionResult = State.PASS

        elif attribute == 'className':
            selector = self._device.retrieveSelector(point, self._device.d(className=value))
            if selector:
                if selector.childCount == 0:
                    self.actionResult = State.PASS
            else:
                self.actionResult = State.PASS

    def actionCheckExist(self, param, refer=None):
        """
        Check the target view whether is existed on the screen.
        :param param: [Identification, x, y]. There are 4 kinds of identification(resourceId, text, description, className).
        :param refer: None
        """
        benchmark, x, y = param
        attribute, value = benchmark.split('=')
        point = (int(x), int(y))
        if attribute == 'text':
            if self._device.retrieveSelector(point, self._device.d(text=value)):
                self.actionResult = State.PASS
                # self.report.emit(INFO, 'Pass: View exist', True)
            else:
                pass
                # self.report.emit(ERROR, 'Fail: View not exist', True)
                # self.isStopRun = True
        elif attribute == 'description':
            if self._device.retrieveSelector(point, self._device.d(description=value)):
                self.actionResult = State.PASS
                # self.report.emit(INFO, 'Pass: View exist', True)
            else:
                pass
                # self.report.emit(ERROR, 'Fail: View not exist', True)
                # self.isStopRun = True
        elif attribute == 'resourceId':
            if self._device.retrieveSelector(point, self._device.d(resourceId=value)):
                self.actionResult = State.PASS
                # self.report.emit(INFO, 'Pass: View exist', True)
            else:
                pass
                # self.report.emit(ERROR, 'Fail: View not exist', True)
                # self.isStopRun = True
        elif attribute == 'className':
            if self._device.retrieveSelector(point, self._device.d(className=value)):
                self.actionResult = State.PASS
                # self.report.emit(INFO, 'Pass: View exist', True)
            else:
                pass
                # self.report.emit(ERROR, 'Fail: View not exist', True)
                # self.isStopRun = True

    def actionCheckNoExist(self, param, refer=None):
        """
        Check the target view whether isn't existed on the screen.
        :param param: [Identification, x, y]. There are 4 kinds of identification(resourceId, text, description, className).
        :param refer: None
        """
        benchmark, x, y = param
        attribute, value = benchmark.split('=')
        point = (int(x), int(y))
        if attribute == 'text':
            if not self._device.retrieveSelector(point, self._device.d(text=value)):
                self.actionResult = State.PASS

        elif attribute == 'description':
            if not self._device.retrieveSelector(point, self._device.d(description=value)):
                self.actionResult = State.PASS

        elif attribute == 'resourceId':
            if not self._device.retrieveSelector(point, self._device.d(resourceId=value)):
                self.actionResult = State.PASS

        elif attribute == 'className':
            if not self._device.retrieveSelector(point, self._device.d(className=value)):
                self.actionResult = State.PASS

    def actionHideKeyboard(self, param, refer=None):
        """
        Hide soft keyboard. If keyboard isn't showed, it will do nothing.
        :param param: None
        :param refer: None
        """
        self._device.hideKeyboard()
        self.actionResult = State.PASS

    def stop(self):
        """
        Exit this process.
        """
        self.isStopRun = True

    def setStartIndex(self, index):
        """
        chose a start index of actions.
        :param index: integer
        """
        self.startIndex = index

    def takeScreenShot(self, path):
        self.picData = self.miniReader.getDisplay()
        self.picImage.loadFromData(self.picData)
        self.picImage.save(path, 'JPEG')

    def run(self):
        self.isStopRun = False
        self.limit = 0
        try:
            self.miniServer.start()
            ''' wait for active '''
            while not self.miniServer.isActive():
                time.sleep(0.5)
            self.takeScreenShot(Global.IMAGE_FOLDER + '/%s_%d.jpg' % (self.playName, 0))
            while self.limit < self.times and not self.isStopRun:
                self.limit += 1
                for index in range(len(self.actions)):
                    if not self.isStopRun and self.startIndex <= index:
                        self.index = index + 1
                        item = self.actions[index]
                        if self._device.isConnected():
                            self.actionResult = State.FAIL
                            self.currentAction.emit(item)
                            self.actionSwitcher.get(item.action())(item.parameter(), item.information())
                            self.actionDone.emit(item, self.actionResult, index)
                            self.takeScreenShot(Global.IMAGE_FOLDER + '/%s_%d.jpg' % (self.playName, self.index))
                            time.sleep(0.5)

                        else:
                            self.isStopRun = True
                            break
        except socket.error:
            print 'socket.error: device offline'
            self.isStopRun = True
        except ValueError as e:
            print 'ValueError: ' + e.message
            self.isStopRun = True
        except CalledProcessError, exc:
            print 'CalledProcessError: ' + str(exc)
            self.isStopRun = True
        finally:
class UpdateScreen(QtCore.QThread):
    """
    Keep capturing screen in the background.
    """
    loadDone = QtCore.Signal()
    startLoad = QtCore.Signal()
    deviceOffline = QtCore.Signal()
    isStop = False
    isPause = False

    def __init__(self, device, picPath):
        super(UpdateScreen, self).__init__()
        self.isStop = False
        self._device = device
        self.delay = 0
        self.picPath = picPath
        self.lastFrameTime = 0
        self.isRefresh = False
        self.nconcurrent = threading.BoundedSemaphore(5)
        self.miniServer = MiniServer(self._device)
        self.miniReader = MiniReader(self._device)

    def stop(self):
        """ Stop capturing """
        self.isStop = True
        self.miniServer.stop()

    # def pause(self):
    #     """ Pause capturing """
    #     self.isPause = True
    #     self.miniServer.stop()
    #
    # def resume(self):
    #     """ resume capturing """
    #     self.isPause = False
    #     # self.start()

    def setDelay(self, delay=0):
        """ Set a delay time to start capturing """
        self.delay = delay

    def run(self):
        time.sleep(self.delay)
        try:
            self.miniServer.start()
            self.isStop = False
            while not self.isStop:
                if self.miniServer.isActive():
                    if not self.miniServer.needRestart():
                        self.startLoad.emit()
                        self.screenshot(path=self.picPath + '/' + self._device.serialno + '_screen.jpg')
                    else:
                        self.miniServer.reStart()
                else:
                    time.sleep(0.5)
                    # self.isPause = True
        except:
            print 'device not found'
            self.lastFrameTime = 0
            self.deviceOffline.emit()
        finally:
            self.miniServer.stop()

    def monitorFrame(self):
        """
        monitor the screen has changed, it helps to reduce capturing frequency.
        """
        decryptRE = re.compile('\s+events-delivered:\s+(?P<number>\d+)')
        output = self._device.cmd.dumpsys(['SurfaceFlinger'])
        if output:
            m = decryptRE.search(output)
            if m is not None:
                tmpTime = m.group('number')
                if tmpTime != self.lastFrameTime:
                    self.lastFrameTime = tmpTime
                    return True

    def screenshot(self, path, delay=0):
        """
        Do screen capture
        :param path: save pic path
        :param delay: delay to capture screen. In second.
        """
        try:
            # self.nconcurrent.acquire()
            time.sleep(delay)
            pp = time.time()
            if self._device.isConnected():
                if self.miniServer.isActive():
                    byteData = self.miniReader.getDisplay()
                    im = QtGui.QImage.fromData(QtCore.QByteArray.fromRawData(byteData))
                    im.loadFromData(byteData)
                    im.save(path, 'JPEG')
            else:
                if not self.isStop:
                    self.deviceOffline.emit()
            print time.time() - pp
            if not self.isStop:
                self.loadDone.emit()
        except AttributeError as e:
            print e.message
        except IOError as e:
            print e.message
        # finally:
        #     self.nconcurrent.release()

    def __byteToHex(self, bs):
        return ''.join(['%02X ' % ord(byte) for byte in bs])

    def __parsePicSize(self, data):
        return int(binascii.hexlify(data[::-1]), 16)

    def __parseBanner(self, data):
        if len(data) == 24:
            banner = dict()
            banner['version'] = int(binascii.hexlify(data[0]), 16)
            banner['length'] = int(binascii.hexlify(data[1]), 16)
            banner['pid'] = int(binascii.hexlify(data[2:5][::-1]), 16)
            banner['real.width'] = int(binascii.hexlify(data[6:9][::-1]), 16)
            banner['real.height'] = int(binascii.hexlify(data[10:13][::-1]), 16)
            banner['virtual.width'] = int(binascii.hexlify(data[14:17][::-1]), 16)
            banner['virtual.height'] = int(binascii.hexlify(data[18:21][::-1]), 16)
            banner['orient'] = int(binascii.hexlify(data[22]), 16)
            banner['policy'] = int(binascii.hexlify(data[23]), 16)
            return banner
 def setMinicap(self):
     self.miniReader = MiniReader(self._device)
     self.miniServer = MiniServer(self._device)