Exemplo n.º 1
0
    def is_playing(self):
        vc = ViewClient(self.device, self.serialno)
        play_pause_header_key = GoogleMusicApp.PLAY_PAUSE_HEADER_KEY
        play_pause_btn_view = [
            v for v in vc.getViewsById().values()
            if v.getId() == play_pause_header_key
        ]
        play_pause_btn_view = play_pause_btn_view[0] if len(
            play_pause_btn_view) > 0 else None

        if play_pause_btn_view:
            return self.check_play_status(
                utf8str(play_pause_btn_view.getContentDescription()))

        ctrl_panel_play_pause_key = GoogleMusicApp.CONTROL_PANEL_PLAY_PAUSE_KEY
        ctrl_panel_play_pause_view = [
            v for v in vc.getViewsById().values()
            if v.getId() == ctrl_panel_play_pause_key
        ]
        ctrl_panel_play_pause_view = ctrl_panel_play_pause_view[0] if len(
            ctrl_panel_play_pause_view) > 0 else None

        if ctrl_panel_play_pause_view:
            return self.check_play_status(
                utf8str(ctrl_panel_play_pause_view.getContentDescription()))

        return False
def main():
    device, serialno = ViewClient.connectToDeviceOrExit(serialno=None)
    vc = ViewClient(device, serialno)
    views_dict = vc.getViewsById()

    print(
        "-------- Show the detail in the returned by the API ViewClient.getViewsById() --------"
    )
    for key, value in views_dict.items():
        print("{}:\n{}\n".format(key, unicode(value).encode("UTF-8")))

    views = filter(lambda v: len(v.getId()) > 0, views_dict.values())
    id_view_dict = {}
    for v in views:
        if v.getId() in id_view_dict.keys():
            id_view_dict[v.getId()].append(v)
        else:
            id_view_dict[v.getId()] = [v]

    print("\n")
    print("-------- Print the id-to-view pairs --------")
    for key, value in id_view_dict.items():
        for each in value:
            print("{}:\n{}\n".format(key, unicode(each).encode("UTF-8")))

    vc.traverse()

    pass
    def _fetch_songs(self):
        vc = ViewClient(self.device, self.serialno, autodump=False)
        songs = {}
        drag_up_count = 0
        li_title_key = GoogleMusicApp.LI_TITLE_KEY
        while True:
            song_props = self._fetch_songs_on_current_screen(vc=vc)
            song_props = filter(lambda prop: not prop[0] in songs.keys(), song_props)
            if len(song_props) == 0:
                break
            for name, duration in song_props:
                v = [v for v in vc.getViewsById().values() if v.getId() == li_title_key and utf8str(v.getText()) == name]
                if len(v) != 1:
                    self.push_dump("in _fetch_songs, got multiple songs with the same name '{}'".format(name))
                v = v[0] if len(v) > 0 else None
                songs[name] = {
                    "duration": duration,
                    "drag_up_count": drag_up_count,
                    "position": v.getCenter() if v else (-1, -1)
                }
            self._drag_up()
            drag_up_count += 1

        for name, info in songs.items():
            self.push_dump("{}: {}".format(name, info))

        return songs
Exemplo n.º 4
0
def get_boomsound_id(device, serialno):
    vc = ViewClient(device, serialno)
    view_dict = vc.getViewsById()
    for key, value in view_dict.items():
        strTemp = unicode(value).encode("UTF-8")
        if strTemp.find("text=HTC BoomSound") > 0:
            return vc, key
    return None, None
Exemplo n.º 5
0
def get_play_pause_id(device, serialno):
    vc = ViewClient(device, serialno)
    view_dict = vc.getViewsById()
    for key, value in view_dict.items():
        strTemp = unicode(value).encode("UTF-8")
        if strTemp.find("id/play_controls") > 0:
            return vc, key
    return None, None
Exemplo n.º 6
0
def get_callDuration_id(device, serialno):
    vc = ViewClient(device, serialno)
    view_dict = vc.getViewsById()
    for key, value in view_dict.items():
        strTemp = unicode(value).encode("UTF-8")
        if strTemp.find("id/callDuration") > 0:
            return True
    return False
Exemplo n.º 7
0
def get_menu_id(device, serialno):
    vc = ViewClient(device, serialno)
    view_dict = vc.getViewsById()
    for key, value in view_dict.items():
        strTemp = unicode(value).encode("UTF-8")
        if strTemp.find("content-desc=More options") > 0:
            return vc, key
    return None, None
Exemplo n.º 8
0
def get_rename_edit_id(device, serialno):
    vc = ViewClient(device, serialno)
    view_dict = vc.getViewsById()
    for key, value in view_dict.items():
        strTemp = unicode(value).encode("UTF-8")
        if strTemp.find("id/textName") > 0:
            return vc, key
    return None, None
Exemplo n.º 9
0
def get_normal_id(device, serialno):
    vc = ViewClient(device, serialno)
    view_dict = vc.getViewsById()
    for key, value in view_dict.items():
        strTemp = unicode(value).encode("UTF-8")
        if strTemp.find("text=Normal quality (AMR_NB)") > 0:
            return vc, key
    return None, None
Exemplo n.º 10
0
def get_flac_id(device, serialno):
    vc = ViewClient(device, serialno)
    view_dict = vc.getViewsById()
    for key, value in view_dict.items():
        strTemp = unicode(value).encode("UTF-8")
        if strTemp.find("text=High res quality (FLAC)") > 0:
            return vc, key
    return None, None
Exemplo n.º 11
0
def get_ArtPager_id(device, serialno):
    vc = ViewClient(device, serialno)
    view_dict = vc.getViewsById()
    for key, value in view_dict.items():
        strTemp = unicode(value).encode("UTF-8")
        if strTemp.find("id/art_pager") > 0:
            return vc, key
    return None
Exemplo n.º 12
0
def get_fragment_list_view(device, serialno):
    vc = ViewClient(device, serialno)
    view_dict = vc.getViewsById()
    for key, value in view_dict.items():
        strTemp = unicode(value).encode("UTF-8")
        if strTemp.find("id/fragment_list") > 0:
            view = vc.findViewByIdOrRaise(key)
            return view
    return None
Exemplo n.º 13
0
def get_callStateLable_id(device, serialno):
    vc = ViewClient(device, serialno)
    view_dict = vc.getViewsById()
    for key, value in view_dict.items():
        strTemp = unicode(value).encode("UTF-8")
        if strTemp.find("text=DIALING") > 0 and strTemp.find(
                "id/callStateLable") > 0:
            return True
    return False
Exemplo n.º 14
0
def main(output_path="out.png"):
    device, serialno = ViewClient.connectToDeviceOrExit(serialno=None)
    vc = ViewClient(device, serialno)

    img = np.array(device.takeSnapshot())
    plt.imshow(img)

    views_dict = vc.getViewsById()
    # clickables = filter(lambda v: v.getClickable(), views_dict.values())
    # views = clickables
    views = views_dict.values()

    for v in views:
        min_c, max_c = v.getBounds()
        draw_rect(min_c, max_c, style="r--", linewidth=1)
        plt.annotate(v.getId().split("/")[-1] if len(v.getId()) > 0 else "\"empty\"", xy=v.getCenter(),
            horizontalalignment="center", verticalalignment="center", color="b", size=2.5)

    plt.gca().get_xaxis().set_visible(False)
    plt.gca().get_yaxis().set_visible(False)
    plt.savefig(output_path, bbox_inches="tight", pad_inches=0, dpi=300)

    pass    
Exemplo n.º 15
0
def testAppFromTestcase(apkPath,
                        testCaseFile,
                        avdSerialno="",
                        waitInterval=1,
                        takeSnapshots=False,
                        allowCrashes=False,
                        uninstallApp=True):
    """
    Tests an app according to a specific test case loaded from a JSON file generated by a previous test
    :param apkPath: The path to the APK to test
    :type apkPath: str
    :param testCaseFile: The path to the test case file from whence the actions are loaded
    :type testCaseFile: str
    :param avdSerialno: The serial number of the Android virtual device (in case multiple devices are running simultaneously)
    :type avdSerialno: str
    :param waitInterval: The time (in seconds) to wait between actions
    :type waitInterval: int 
    :param takeSnapshots: Whether to take snapshots of the device screen after every performed action (default: False)
    :type takeSnapshots: bool
    :param allowCrashes: Whether to allow the app under test to crash. If (by default) False, the app will be re-started and re-tested.
    :type allowCrashes: bool
    :param uninstallApp: Whether to uninstall the app under test before returning
    :type uninstallApp: bool
    :return: A bool indicating the success/failure of the test
    """
    try:
        # 1. Connect to the virtual device
        prettyPrint("Connecting to device", "debug")
        if avdSerialno != "":
            vc = ViewClient(*ViewClient.connectToDeviceOrExit(
                ignoreversioncheck=True, verbose=True, serialno=avdSerialno))
        else:
            vc = ViewClient(*ViewClient.connectToDeviceOrExit(
                ignoreversioncheck=True, verbose=True))

        # 1.a. Analyzing app
        prettyPrint("Analyzing app using \"androguard\"", "debug")
        apk, dx, vm = analyzeAPK(apkPath)
        appComponents = extractAppComponents(apk)

        # 2. Install package and configure Introspy (if requested)
        prettyPrint("Installing package \"%s\"" % apkPath, "debug")
        subprocess.call([vc.adb, "-s", avdSerialno, "install", "-r", apkPath])

        # 3. Load and parse test case file
        prettyPrint("Loading the test case file \"%s\"" % testCaseFile,
                    "debug")
        if not os.path.exists(testCaseFile):
            prettyPrint("Could not find the test case file", "error")
            return False
        content = json.loads(open(testCaseFile).read())
        if len(content["events"]) < 1:
            prettyPrint("Could not retrieve events to run", "error")

        # 4. Iterate over events and execute them
        tapEvents = [
            "Button", "CheckBox", "RadioButton", "Switch", "ToggleButton"
        ]
        touchEvents = ["longtouch", "touch"]
        textEvents = ["EditText"]
        swipeEvents = ["swipeleft", "swiperight"]
        pressEvents = ["press"]
        for e in content["events"]:
            # 4.1. Parse and execute event
            if e["type"] == "activity":
                try:
                    prettyPrint("Starting activity \"%s\"" % e["id"], "debug")
                    vc.device.startActivity(e["id"])
                except exceptions.RuntimeError as rte:
                    prettyPrint("Unable to start activity \"%s\"" % e["id"],
                                "warning")
            elif e["type"] == "broadcast":
                prettyPrint("Broadcasting intent action: %s" % e["intent"],
                            "debug")
                vc.device.shell("am broadcast -a %s" % e["intent"])
            elif e["type"] in tapEvents:
                prettyPrint(
                    "Tapping %s at (%s, %s)" % (e["type"], e["x"], e["y"]),
                    "debug")
                vc.touch(int(e["x"]), int(e["y"]))
            elif e["type"] in textEvents:
                prettyPrint(
                    "Writing \"%s\" to EditText field \"%s\"" %
                    (e["text"], e["id"]), "debug")
                allviews = vc.getViewsById()
                if len(allviews) < 1 or e["id"] not in allviews.keys():
                    prettyPrint(
                        "Could not find EditText with id \"%s\". Skipping" %
                        e["id"], "warning")
                else:
                    allviews[e["id"]].setText(e["text"])
            elif e["type"] in swipeEvents:
                prettyPrint(
                    "Swiping screen from (%s, %s) to (%s, %s)" %
                    (e["x"], e["y"], e["xd"], e["yd"]), "debug")
                vc.swipe(int(e["x"]), int(e["y"]), int(e["xd"]), int(e["yd"]))
            elif e["type"] in pressEvents:
                prettyPrint("Pressing \"%s\"" % e["key"], "debug")
                vc.device.press(e["key"])
            elif e["type"].lower().find("touch") != -1:
                if e["type"] == "longtouch":
                    prettyPrint("Long touching at (%s,%s)" % (e["x"], e["y"]),
                                "debug")
                    vc.longTouch(int(e["x"]), int(e["y"]))
                else:
                    prettyPrint("Touching at (%s,%s)" % (e["x"], e["y"]),
                                "debug")
                    vc.touch(int(e["x"]), int(e["y"]))

            # 4.2. Wait for [waitInterval] seconds and take a snapshot if instructed to
            if waitInterval > 0:
                prettyPrint("Waiting for %s seconds" % waitInterval, "debug")
                time.sleep(waitInterval)
                if takeSnapshots:
                    prettyPrint("Taking snapshot", "debug")
                    snapshot = vc.device.takeSnapshot()
                    snapshot.save(
                        "%s_%s.png" %
                        (appComponents["package_name"], str(int(time.time()))))

            # 4.3. Check whether the performed action crashed or stopped (sent to background) the app
            if _appCrashed(vc, avdSerialno):
                if not allowCrashes:
                    prettyPrint(
                        "The previous action(s) caused the app to crash. Exiting",
                        "warning")
                    if uninstallApp:
                        prettyPrint("Uninstalling app \"%s\"" %
                                    appComponents["package_name"])
                        subprocess.call([
                            vc.adb, "-s", avdSerialno, "uninstall",
                            appComponents["package_name"]
                        ])
                    return False
                prettyPrint(
                    "The previous action(s) caused the app to crash. Restarting",
                    "warning")
                vc.device.startActivity("%s/%s" %
                                        (appComponents["package_name"],
                                         appComponents["main_activity"]))
                time.sleep(
                    waitInterval)  # Give time for the main activity to start
            elif _appStopped(vc, appComponents, avdSerialno):
                prettyPrint(
                    "The previous action(s) stopped the app. Restarting",
                    "warning")
                vc.device.startActivity("%s/%s" %
                                        (appComponents["package_name"],
                                         appComponents["main_activity"]))
                time.sleep(
                    waitInterval)  # Give time for the main activity to start

        # 6. Uninstalling app under test
        if uninstallApp:
            prettyPrint("Uninstalling app \"%s\"" %
                        appComponents["package_name"])
            subprocess.call([
                vc.adb, "-s", avdSerialno, "uninstall",
                appComponents["package_name"]
            ])

    except Exception as e:
        prettyPrintError(e)
        return False

    return True
Exemplo n.º 16
0
    class SSRDumpListenerThread(threading.Thread):
        class State(object):
            IDLE = "idle"
            BEING_DUMPED = "being dumped"
            DUMPED = "has been dumped"

        def __init__(self, device, serialno):
            super(SSRDumpListener.SSRDumpListenerThread, self).__init__()
            self.daemon = True
            self.stoprequest = threading.Event()
            self.lock = threading.Lock()
            self.device = device
            self.serialno = serialno
            self.vc = ViewClient(device, serialno, autodump=False)
            self.state = SSRDumpListener.SSRDumpListenerThread.State.IDLE

        def join(self, timeout=None):
            self.stoprequest.set()
            super(SSRDumpListener.SSRDumpListenerThread, self).join(timeout)

        def run(self):
            pattern = re.compile("Window{.+?}")
            while not self.stoprequest.isSet():
                try:
                    win_dumpsys, _ = subprocess.Popen( \
                        "adb -s {} shell dumpsys window windows | grep \"Window #\"".format(self.serialno), \
                        shell=True, stdout=subprocess.PIPE).communicate()

                    win_info_strs = map(
                        lambda s: pattern.search(s.strip()).group(0),
                        win_dumpsys.splitlines())
                    win_info_strs = [
                        s[7:-1] for s in win_info_strs if len(s) > 7
                    ]
                    self.win_info = dict([
                        (ss[2], ss[0])
                        for ss in map(lambda s: s.split(), win_info_strs)
                    ])
                    if SSRDumpListener.FILTER in self.win_info.keys():
                        self.vc.dump(
                            window=self.win_info[SSRDumpListener.FILTER],
                            sleep=0)
                        views = dict([(v.getId(), v)
                                      for v in self.vc.getViewsById().values()
                                      if len(v.getId()) > 0])

                        if SSRDumpListener.MSG_VIEW_ID in views.keys():
                            msg = views[SSRDumpListener.MSG_VIEW_ID].getText()

                            if SSRDumpListener.RAMDUMP_COMPLETED_KEYMSG in msg:
                                self.state = SSRDumpListener.SSRDumpListenerThread.State.DUMPED
                            else:
                                self.state = SSRDumpListener.SSRDumpListenerThread.State.BEING_DUMPED

                    else:
                        self.state = SSRDumpListener.SSRDumpListenerThread.State.IDLE

                except:
                    pass
                time.sleep(SSRDumpListener.PERIOD)

        def dismiss_dialog(self):
            if self.state == SSRDumpListener.SSRDumpListenerThread.State.IDLE:
                return

            self.vc.dump(window=self.win_info[SSRDumpListener.FILTER], sleep=0)
            views = dict([(v.getId(), v)
                          for v in self.vc.getViewsById().values()
                          if len(v.getId()) > 0])

            if SSRDumpListener.BTN_ID in views.keys():
                x, y = views[SSRDumpListener.BTN_ID].getCenter()
                self.device.touch(x, y)

            self.state = SSRDumpListener.SSRDumpListenerThread.State.IDLE
Exemplo n.º 17
0
    def walk_through(self):
        if not self.to_top():
            Logger.log("GoogleMusicApp", "walk_through failed: unable to go to top activity")
            self.cache_init = False
            return False

        # Get the playcard titles
        vc = ViewClient(self.device, self.serialno)

        self.cache_init = True

        container_key = GoogleMusicApp.CONTAINER_KEY
        container = [v for v in vc.getViewsById().values() if v.getId() == container_key]
        container = container[0] if len(container) > 0 else None
        if container:
            self.cache["screen-info"] = container.getBounds()[1]
            self.push_dump("screen-info: {}".format(self.cache["screen-info"]))

        so = sio.StringIO()
        vc.traverse(stream=so)
        lines = so.getvalue().splitlines()
        play_card_key = GoogleMusicApp.PLAY_CARD_KEY
        playcards_idices = [idx for idx, line in enumerate(lines) if play_card_key in line]
        playcards_idices.append(len(lines))
        playcards_titles = []
        last_idx = playcards_idices[0]

        li_title_key = GoogleMusicApp.LI_TITLE_KEY
        for idx in playcards_idices[1:]:
            li_title_texts = [line for line in lines[last_idx:idx] if li_title_key in line]
            last_idx = idx

            if len(li_title_texts) != 1:
                self.push_dump("li_title_texts has length {}".format(len(li_title_texts)))

            playcards_titles.append(utf8str(li_title_texts[0].split(li_title_key)[-1].strip()))
            self.push_dump("playcards_titles.append('{}')".format(playcards_titles[-1]))

        # Get the track list of each playcard
        views = [v for v in vc.getViewsById().values() if v.getId() == li_title_key and utf8str(v.getText()) in playcards_titles]
        self.cache["playcard"] = dict( \
                map(lambda v: (utf8str(v.getText()), { "position": v.getCenter() }), views)
            )
        map(lambda v: self.push_dump("view: {}".format(utf8str(v))), views)
        map(lambda title: self.push_dump("playcard title: '{}'".format(title)), self.cache["playcard"].keys())

        if len(views) == 0:
            self.cache_init = False
            return False

        self.cache["shuffle_key"] = playcards_titles[0]
        self.push_dump("get the shuffle keyword '{}'".format(self.cache["shuffle_key"]))
        self.touch_playcard(self.cache["shuffle_key"])
        time.sleep(1)

        retry_count = 3
        while retry_count > 0:
            vc.dump()
            play_pause_header_key = GoogleMusicApp.PLAY_PAUSE_HEADER_KEY
            play_pause_btn_view = [v for v in vc.getViewsById().values() if v.getId() == play_pause_header_key]
            play_pause_btn_view = play_pause_btn_view[0] if len(play_pause_btn_view) > 0 else None
            if play_pause_btn_view:
                play_desc = utf8str(play_pause_btn_view.getContentDescription())
                self.check_play_status = lambda desc: desc == play_desc
                self.cache["play_pause_btn"] = { "position": play_pause_btn_view.getCenter(), "desc_feat": play_desc }

                art_pager_key = GoogleMusicApp.ART_PAGER_KEY
                art_pager_view = [v for v in vc.getViewsById().values() if v.getId() == art_pager_key]
                art_pager_view = art_pager_view[0] if len(art_pager_view) > 0 else None
                if not art_pager_view:
                    retry_count -= 1
                    continue
                self.cache["art_pager_view"] = { "position": art_pager_view.getCenter() }

                play_pause_btn_view.touch()
                break
            else:
                self.push_dump("cannot find the play/pause button, retry: {}".format(retry_count))
                retry_count -= 1

        if retry_count == 0:
            return False

        for li_title in self.cache["playcard"].keys():
            if li_title == self.cache["shuffle_key"]:
                continue
            self.push_dump("now fetching information in the playcard '{}'".format(li_title))
            if self.touch_playcard(li_title=li_title):
                time.sleep(1)
                self.cache["playcard"][li_title]["songs"] = self._fetch_songs()
                self.to_top()

        # Get the information of the control panel
        retry_count = 3
        while self.get_state() != GoogleMusicApp.State.CONTROL_PANEL and retry_count > 0:
            self.device.touch(*self.cache["art_pager_view"]["position"])
            retry_count -= 1

        if retry_count == 0 and self.get_state() != GoogleMusicApp.State.CONTROL_PANEL:
            self.to_top()
            time.sleep(5)
            self.touch_playcard(self.cache["shuffle_key"])
            time.sleep(2)
            self.device.touch(*self.cache["play_pause_btn"]["position"])
            time.sleep(2)
            self.device.touch(*self.cache["art_pager_view"]["position"])
            time.sleep(2)
            if self.get_state() != GoogleMusicApp.State.CONTROL_PANEL:
                self.push_dump("cannot get the information of the control panel")
                self.cache_init = False
                return False

        def find_view_position(vc, res_id):
            v = [v for v in vc.getViewsById().values() if v.getId() == res_id]
            if len(v) == 0:
                return ((-1, -1), (-1, -1)), (-1, -1)
            return v[0].getBounds(), v[0].getCenter()

        vc.dump()
        progress_bounds, progress_pos = find_view_position(vc, GoogleMusicApp.CONTROL_PANEL_PROGRESS_KEY)
        self.cache["control_panel"] = {
            "progress": { "position": progress_pos, "xbounds": [progress_bounds[0][0], progress_bounds[1][0]] },
            "prev": { "position": find_view_position(vc, GoogleMusicApp.CONTROL_PANEL_PREV_KEY)[1] },
            "next": { "position": find_view_position(vc, GoogleMusicApp.CONTROL_PANEL_NEXT_KEY)[1] },
            "play_pause": { "position": find_view_position(vc, GoogleMusicApp.CONTROL_PANEL_PLAY_PAUSE_KEY)[1] }
        }
        self.control_panel = GMControlPanel(self)
        self.push_dump("successfully walked through, now back to top")
        self.to_top()

        self.cache_init = True
        return True