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?

Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Jul 28, 2016 at 18:50
\$\endgroup\$
0

1 Answer 1

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("."));
answered Jul 29, 2016 at 13:27
\$\endgroup\$
3
  • \$\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\$ Commented Jul 29, 2016 at 14:29
  • \$\begingroup\$ Anymore comments sir ? \$\endgroup\$ Commented Jul 31, 2016 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\$ Commented Jul 31, 2016 at 9:28

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.