Android Open Source - UbarCDC Ubar Acc Service






From Project

Back to project page UbarCDC.

License

The source code is released under:

Apache License

If you think the Android project UbarCDC listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.ubergrund.UbarCDC;
// w w  w .  j a va 2s.co  m
import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;

/**
 * Uses the Android Accessibility Service to "remote-control" the
 * Google Music App, as there seems no way to open an album and
 * also start playing.
 *
 * UbarCDC
 * Copyright (C) 2013 Tim Otto
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Created with IntelliJ IDEA.
 * User: Tim
 * Date: 9/15/13
 * Time: 1:53 PM
 */
public class UbarAccService extends AccessibilityService {

    private static final String TAG = "UbarCDC/UbarAccService";
    /**
     * ACTION!!
     */
    public static final String EXTRA_GEYGUARD_ENABLE = "keyguard_enable";
    public static final String EXTRA_ACTION = "action";
    public static final String VALUE_PLAY = "play";
    public static final String VALUE_RADIO = "radio";
    public static final String VALUE_SHUFFLE = "shuffle";

    private int inspectorState = 0;
    private AccessibilityNodeInfo playView = null;
    private AccessibilityNodeInfo radioView = null;
    private AccessibilityNodeInfo shuffleView = null;
    private AccessibilityNodeInfo menuView = null;

    private boolean armed = false;
    private String action = null;
    private boolean reEnableKeyguard = false;

    private void onButtonsFound() {
        Log.d(TAG, "onButtonsFound()");
        armed=false;
        if (VALUE_PLAY.equals(action))
            playView.performAction(AccessibilityNodeInfo.ACTION_CLICK);
        else if (VALUE_RADIO.equals(action))
            radioView.performAction(AccessibilityNodeInfo.ACTION_CLICK);
        else if (VALUE_SHUFFLE.equals(action))
            shuffleView.performAction(AccessibilityNodeInfo.ACTION_CLICK);

        performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);

        final Intent intent = new Intent(UbarAccService.this, GoogleMusicHelperService.class);
        intent.setAction(GoogleMusicHelperService.ACTION_FINISH);
        if (reEnableKeyguard) {
            Log.d(TAG, "going to re-enable keyguard");
            intent.putExtra(GoogleMusicHelperService.EXTRA_LOCK, true);
        }
        startService(intent);

        playView.recycle();
        radioView.recycle();
        shuffleView.recycle();
        playView=null;
        radioView=null;
        shuffleView=null;
        Log.d(TAG, "done with onButtonsFound()");
    }

    private void onMenuFound() {
        Log.d(TAG, "onMenuFound()");
        menuView.performAction(AccessibilityNodeInfo.ACTION_CLICK);
    }

    @Override
    public void onCreate() {
        super.onCreate();
        registerReceiver(actionReceiver, new IntentFilter("com.ubergrund.ubarcdc.CDC_GM_HACK"));
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        unregisterReceiver(actionReceiver);
    }

    private final BroadcastReceiver actionReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if(intent==null)return;
            action = intent.getStringExtra(EXTRA_ACTION);
            reEnableKeyguard = intent.getBooleanExtra(EXTRA_GEYGUARD_ENABLE, false);
            armed = (action!=null);
            Log.d(TAG, armed?"Armed!"+(reEnableKeyguard?" + re-enable":""):"Disarmed!");
        }
    };

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        if(!armed)return;
        if (event==null)return;
        try {
//            Log.d(TAG, "event ["+event+"]");
            AccessibilityNodeInfo source = event.getSource();
            AccessibilityNodeInfo parent = source.getParent();
            AccessibilityNodeInfo root = null;

//            Log.d(TAG, "source [" + source + "]");
            while (parent != null) {
    //            Log.d(TAG, "parent [" + parent + "]");
                source.recycle();
                source = parent;
                parent = source.getParent();
            }

            root = source;
//            Log.d(TAG, "root [" + root + "]");
            resetInspector();
            inspectNode(root);
        } catch (NullPointerException ignored) {
//            Log.e(TAG, "Error", e);
        }
    }

    private void resetInspector() {
        inspectorState=0;
    }

    private static final String RES_ID_ALBUM_ART = "com.google.android.music:id/album_art";
    private static final String RES_ID_PIN_BUTTON = "com.google.android.music:id/pin_button";
    private static final String RES_ID_OVERFLOW = "com.google.android.music:id/overflow";
    private static final String RES_ID_TEXT1 = "android:id/text1";
    private static final String RES_ID_POPUPLIST = "com.google.android.music:id/popup_list";
    private static final String RES_ID_PLAY_RADIO = "com.google.android.music:id/play_radio";
    private static final String RES_ID_SHUFFLE = "com.google.android.music:id/shuffle";

    private boolean omgwt(AccessibilityNodeInfo info) {
        final String resName = info.getViewIdResourceName();
        switch (inspectorState) {
            case 0:
                if (RES_ID_ALBUM_ART.equals(resName)) {
                    if (playView!=null)playView.recycle();
                    playView = info;
                    inspectorState=1;
                    return true;
                }
                if (RES_ID_POPUPLIST.equals(resName)) {
                    inspectorState = 3;
                    return false;
                }
                return false;

            case 1:
                if (RES_ID_PIN_BUTTON.equals(resName)) {
                    inspectorState = 2;
                    return false;
                }

                if (RES_ID_PLAY_RADIO.equals(resName)) {
                    if (radioView!=null)radioView.recycle();
                    radioView = info;
                    inspectorState = 5;
                    return true;
                }
                break;

            case 2:
                if (RES_ID_OVERFLOW.equals(resName)) {
                    if (menuView!=null)menuView.recycle();
                    menuView = info;
                    if (VALUE_PLAY.equals(action))
                        onButtonsFound();
                    else
                         onMenuFound();
                    return true;
                }
                break;

            case 3:
                if (RES_ID_TEXT1.equals(resName)) {
                    // TODO confirm menu text vs i18n values/strings
                    if (radioView!=null)radioView.recycle();
                    radioView = info;
                    inspectorState = 4;
                    return true;
                }
                break;

            case 4:
                if (RES_ID_TEXT1.equals(resName)) {
                    // TODO confirm menu text vs i18n values/strings
                    if (shuffleView!=null)shuffleView.recycle();
                    shuffleView = info;
                    onButtonsFound();
                    return true;
                }
                break;

            case 5:
                if (RES_ID_SHUFFLE.equals(resName)) {
                    if (shuffleView!=null)shuffleView.recycle();
                    shuffleView = info;
                    onButtonsFound();
                    return true;
                }
                break;

        }
        inspectorState=0;
        return omgwt(info);
    }

    private void inspectNode(AccessibilityNodeInfo info) {
        if (info==null)return;
        boolean keep = false;
        if (info.isClickable() && info.isEnabled()) {
//            Log.d(TAG, "Candidate ["+info.getViewIdResourceName()+"] ["+info+"]");
            keep = omgwt(info);
        }
        final int n = info.getChildCount();
        for(int i=0;i<n;i++) {
            final AccessibilityNodeInfo child = info.getChild(i);
            if (child != null) {
                inspectNode(child);
            }
        }
        if(!keep)
            info.recycle();
    }

    @Override
    public void onInterrupt() {
    }

    @Override
    protected void onServiceConnected() {
        super.onServiceConnected();

        final AccessibilityServiceInfo serviceInfo = getServiceInfo();
        serviceInfo.flags |= AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS;
        setServiceInfo(serviceInfo);

    }
}




Java Source Code List

com.ubergrund.UbarCDC.BluetoothStateReceiver.java
com.ubergrund.UbarCDC.CDCEventReceiver.java
com.ubergrund.UbarCDC.GoogleMusicHelperService.java
com.ubergrund.UbarCDC.MenuProvider.java
com.ubergrund.UbarCDC.MusicSearchActivity.java
com.ubergrund.UbarCDC.SPPDriver.java
com.ubergrund.UbarCDC.StatusInfo.java
com.ubergrund.UbarCDC.UbarAccService.java
com.ubergrund.UbarCDC.UbarCDCService.java
com.ubergrund.UbarCDC.UbarCDC.java