3
\$\begingroup\$

I am currently working on an app in which one of the tasks is to catch the notifications of different applications (phone call, Facebook, Twitter, Whatsapp etc...). Now I will have some values pre-defined for all the pre-defined applications. Values will be of type string denoting R,G,B color values. I would have to send these color values via Bluetooth to another device. For this I have created an accessibility service.

Here is my main activity:

Main Activity displays a listview with applications name declared in the currentlyEnabled HashMap. The newFinalPackages HashMap stores the application names for all the pre defined applications. The apptoRBG HashMap stores these application names with user-given RGB values.

public class MainActivity extends AppCompatActivity {

    private Intent mailAccessabilityIntent;
    private ListView actioList;
    private ActionCustomAdapter adapter;
    private static final String DEFAULT_COLOR = "R:255,G:255,B:255";
    private static HashMap<String, String> newfinalpackages = new HashMap<String, String>();
    private static HashMap<String, String> newappToRGB = new HashMap<String, String>();

    static {
        newfinalpackages.put("dialer", "Calls");
        newfinalpackages.put("whatsapp", "WhatsApp");
        newfinalpackages.put("facebook.katana", "Facebook");
        newfinalpackages.put("twitter", "Twitter");
        newfinalpackages.put("instagram", "Instagram");
        newfinalpackages.put("gmail", "GMail");
        newfinalpackages.put("batterylow", "Low Battery");
        newfinalpackages.put("messenger", "Text Message"); 

        newappToRGB.put("dialer", DEFAULT_COLOR);
        newappToRGB.put("whatsapp", DEFAULT_COLOR);
        newappToRGB.put("facebook", DEFAULT_COLOR);
        newappToRGB.put("twitter", DEFAULT_COLOR);
        newappToRGB.put("instagram", DEFAULT_COLOR);
        newappToRGB.put("gmail", null);
        newappToRGB.put("batterylow", null);
        newappToRGB.put("messenger", null);
    }


    private static HashMap<String, String> currentlyEnabled = new HashMap<String, String>();
    private HashMap<String, String> currentlyDisabled = new HashMap<String, String>();

    public static HashMap<String, String> getCurrentlyEnabled() {
        return currentlyEnabled;
    }

    public static HashMap<String, String> getAppToRGB() {
        return newappToRGB;
    }

    private void DrawSelected() {
        currentlyEnabled.put("dialer", "Calls");
        currentlyEnabled.put("whatsapp", "WhatsApp");
        currentlyEnabled.put("facebook", "Facebook");
        currentlyEnabled.put("twitter", "Twitter");
        currentlyEnabled.put("instagram", "Instagram");
        currentlyDisabled.put("gmail", "GMail");
        currentlyDisabled.put("batterylow", "Low Battery");
        currentlyDisabled.put("messenger", "Text Message");
    }


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent mailAccess = new Intent(MainActivity.this, InstantMessanger.class);
        startService(mailAccess);
        DrawSelected();
        serviceSwitch = (Switch) findViewById(R.id.serviceSwitch); //DIDN'T ADD FUNCTIONALITY YET.
        actioList = (ListView) findViewById(R.id.actionList);

         // Button to add applications from currentlyDisabled to CurrentlyEnabled
         // Not Important here.
        actioList.addFooterView(addEvent);
        adapter = new ActionCustomAdapter(this, currentlyEnabled);    
        actioList.setAdapter(adapter);

           // Just to choose the color value.Nothing Else.
        actioList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                String Item = ((HashMap.Entry<String, String>) adapterView.getItemAtPosition(i)).getKey();
                showColorPickerDialogDemo(Item);
            }
        });

    }

        // IGNORE THIS.
    private void showColorPickerDialogDemo(final String key) {

        int initialColor = Color.WHITE;

        ColorPickerDialog colorPickerDialog = new ColorPickerDialog(this, initialColor, new ColorPickerDialog.OnColorSelectedListener() {

            @Override
            public void onColorSelected(int color) {
                showToast(color);
                appToRGB.put(key, "R: " + Color.red(color) + " B: " + Color.blue(color) + " G: " + Color.green(color));
                InstantMessanger.addEnabledActions(key, "R: " + Color.red(color) + " B: " + Color.blue(color) + " G: " + Color.green(color));
            }

        });
        colorPickerDialog.show();

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }
}

showColorPickerDemo() is for color selection.

My service class is:

When created, the enabledAction HashMap from MainActivity is passed to this class using static methods.

The service class basically catches any notification posted on an Android device by any application with the listener OnAccessibility event. Then it is extracting the actual application name from the package name in the parsePackage() method. Then it checks if this application name is in enabledActions. If yes, it sends the data through Bluetooth (which still needs to be implemented).

public class InstantMessanger extends AccessibilityService {

    private TextView text;
    private String packagename;
    private String selfname = "com.example.sgoel01.checkingevents",download = "com.android.providers.downloads";
    Context context = this;

    private static HashMap<String,String> enabledActions = new HashMap<String, String>();

    public static void addEnabledActions(String key, String value) {
        enabledActions.put(key, value);
    }

    @Override
    public void onCreate() {
        Toast.makeText(this, "Service is Started for the first time", Toast.LENGTH_LONG).show();
        enabledActions = MainActivity.getAppToRGB();
        for(HashMap.Entry<String,String> entry : enabledActions.entrySet()) {
            Log.d("enabledAct", entry.getKey() + " is equal to " + entry.getValue());
        }
        Toast.makeText(this, enabledActions.get("whatsapp"), Toast.LENGTH_SHORT).show();
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Toast.makeText(this, "Service is Started on startcommand", Toast.LENGTH_LONG).show();
        enabledActions = MainActivity.getAppToRGB();
        return Service.START_STICKY;
    }

    public void onAccessibilityEvent(AccessibilityEvent event) {

        //Toast.makeText(this,"Event Catched", Toast.LENGTH_LONG).show();
        if(event.getEventType() == AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED) {
            packagename = String.valueOf(event.getPackageName());
            Log.d("pack/call", packagename);
            parsePackage(packagename);
            if(packagename.equals(selfname)==false && packagename.equals("com.android.providers.downloads")==false) {
                Toast.makeText(this, "Package: "+packagename,Toast.LENGTH_LONG).show();
            }
            if(enabledActions.get(packagename) != null) {
                Toast.makeText(this, "This is Working Now " + packagename , Toast.LENGTH_LONG).show();
            }
        }

    }

    private void parsePackage (String pack) {
        String name = pack.substring(pack.indexOf(".")+1,pack.length());
        char[] array = pack.toCharArray();
        int prev=0;
        for(int i=0,n=pack.length() ; i<n ; i++) {
            String temp="";
            if(i==n-1) {
                temp = pack.substring(prev,i+1);
                Log.d("seetothis", "Name: " + temp +" has value= " + enabledActions.get(temp) );
            }
            else if(pack.charAt(i) == '.') {
                temp = pack.substring(prev,i);
                prev = i+1;
                Log.d("seetothis", "Name: " + temp +" has value= " + enabledActions.get(temp) );
            }
            if(enabledActions.get(temp) != null) {
                Log.d("printout", "Package grabbed is: "+temp+" With Value: "+enabledActions.get(temp));
            }
        }
    }

    @Override
    public void onInterrupt() {

    }

    public static String gettheColor() {
        return enabledActions.get("dialer");
    }

    @Override
    public void onDestroy() {
        Toast.makeText(this, "hUA Nhi ",Toast.LENGTH_SHORT).show();
        super.onDestroy();
    }

    @Override
    protected void onServiceConnected() {
        AccessibilityServiceInfo info = new AccessibilityServiceInfo();
        info.feedbackType = 1;
        info.eventTypes = AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED;
        info.notificationTimeout = 100;
        setServiceInfo(info);
    }

}

Here is my custom adapter for listview on main activity. This is taking the HashMaps and simply displaying in listview.

public class ActionCustomAdapter extends BaseAdapter {

    private Activity activity;
    private ArrayList mData;
    private static LayoutInflater inflater=null;

    public ActionCustomAdapter(Activity a, HashMap<String,String> d) {
        activity = a;
        mData = new ArrayList();
        mData.addAll(d.entrySet());
        inflater = (LayoutInflater)activity.
                getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    @Override
    public int getCount() {
        return mData.size();
    }

    @Override
    public HashMap.Entry<String, String> getItem(int position) {
        return (HashMap.Entry) mData.get(position);
    }

    public long getItemId(int position) {
        return position;
    }


    public View getView(int position, View convertView, ViewGroup parent) {

        View vi=convertView;
        if(convertView==null)
            vi = inflater.inflate(R.layout.list_item_notification, null);

        HashMap.Entry<String, String> item = getItem(position);

        TextView text=(TextView)vi.findViewById(R.id.textAction);;
        ImageView image=(ImageView)vi.findViewById(R.id.imageAction);

        text.setText(item.getValue());
        return vi;
    }


}

Am I declaring too many static methods and variables? Am I passing too much data between the activities?

Also, my service intend to run in the background, so do I need a different set of variables (corresponding string values for different applications) for it always, or can I just extract them from another activity whenever required? Or there is some better way?

\$\endgroup\$
2
\$\begingroup\$
if(packagename.equals(selfname)==false && packagename.equals("com.android.providers.downloads")==false) {
        Toast.makeText(this, "Package: "+packagename,Toast.LENGTH_LONG).show();
}

You can use this check instead:

!packagename.equals(selfname) && !packagename.equals("com.android.providers.downloads")

Explicit equality checks with false seem out of place.


private void parsePackage (String pack) {
    String name = pack.substring(pack.indexOf(".")+1,pack.length());
    char[] array = pack.toCharArray();
    int prev=0;
    for(int i=0,n=pack.length() ; i<n ; i++) {
        String temp="";
        if(i==n-1) {
            temp = pack.substring(prev,i+1);
            Log.d("seetothis", "Name: " + temp +" has value= " + enabledActions.get(temp) );
        }
        else if(pack.charAt(i) == '.') {
            temp = pack.substring(prev,i);
            prev = i+1;
            Log.d("seetothis", "Name: " + temp +" has value= " + enabledActions.get(temp) );
        }
        if(enabledActions.get(temp) != null) {
            Log.d("printout", "Package grabbed is: "+temp+" With Value: "+enabledActions.get(temp));
        }
    }
}

Rather than using a complex loop here, you could make use of String.split, then iterate over the String array afterwards. As String.split takes a regex, you'll want to escape the delimiter:

(Escape method taken from How can I use “.” as the delimiter with String.split() in java)

String[] packageNames = pack.split(Pattern.quote("."));
\$\endgroup\$
  • \$\begingroup\$ Thanks for your answer very much. Also I want to ask if there can be any improvement to the object oriented aspect of the program. \$\endgroup\$ – sgoel Jul 29 '16 at 14:29
  • \$\begingroup\$ Anymore comments sir ? \$\endgroup\$ – sgoel Jul 31 '16 at 1:45
  • \$\begingroup\$ @user3800101 sorry, I'm not familiar with Android's recommended way to split up classes. If you had a object hierarchy separate from android then I could help but I haven't programmed a whole lot of Android before... so I just reviewed it based on the fact you can use regular Java for android \$\endgroup\$ – Pimgd Jul 31 '16 at 9:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.